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

Runtime worker threads #7089

Merged
63 commits merged into from
Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
e9dcebe
std variant
NikVolf Sep 1, 2020
d73ae86
principal work
NikVolf Sep 7, 2020
d1a27f2
format and naming
NikVolf Sep 8, 2020
fbca518
format and naming continued
NikVolf Sep 8, 2020
7472521
working nested fork
NikVolf Sep 11, 2020
8548494
add comment
NikVolf Sep 11, 2020
1249b5a
naming and tabs
NikVolf Sep 15, 2020
abe81dd
line width
NikVolf Sep 15, 2020
612a730
fix wording
NikVolf Sep 15, 2020
b07e0c6
address review
NikVolf Sep 15, 2020
e10a58c
refactor dynamic dispatch
NikVolf Sep 15, 2020
669465a
update wasmtime
NikVolf Sep 15, 2020
2752db3
some care
NikVolf Sep 15, 2020
b001b81
move ext
NikVolf Sep 15, 2020
f7a02fc
more refactor
NikVolf Sep 15, 2020
fdffc76
doc effort
NikVolf Sep 15, 2020
330afa3
simplify
NikVolf Sep 15, 2020
ff8a73c
doc effort
NikVolf Sep 15, 2020
34ec74d
tests and docs
NikVolf Sep 16, 2020
04e7b9f
address review
NikVolf Sep 17, 2020
6708677
naming
NikVolf Sep 17, 2020
80b1cf9
explain some args
NikVolf Sep 17, 2020
5aace98
add example
NikVolf Sep 21, 2020
232bf9a
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Sep 22, 2020
42945f1
unwinding for native and tests
NikVolf Sep 22, 2020
f409af6
rename stray
NikVolf Sep 22, 2020
a7a17ee
fix refs
NikVolf Sep 22, 2020
775d3b1
fix tests
NikVolf Sep 22, 2020
57839a1
fix warnings
NikVolf Sep 22, 2020
14e4a4a
stray naming
NikVolf Sep 22, 2020
33b4987
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Sep 29, 2020
329e92f
fixes and comments
NikVolf Sep 29, 2020
f4f46c8
Update primitives/io/src/tasks.rs
NikVolf Sep 29, 2020
a7d7bd1
make examples "compile"
NikVolf Sep 29, 2020
749d8db
Merge branch 'nv-parallel-runtime' of github.com:paritytech/substrate…
NikVolf Sep 29, 2020
58b36a0
dyn_dispatch -> spawn_call
NikVolf Oct 2, 2020
9defe8f
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Oct 2, 2020
d50047a
fix impl
NikVolf Oct 2, 2020
681aa7b
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Oct 12, 2020
0148582
address review
NikVolf Oct 12, 2020
c507dc2
Update primitives/io/src/lib.rs
NikVolf Oct 12, 2020
80942a6
Update primitives/io/src/tasks.rs
NikVolf Oct 12, 2020
6d92f8e
Update primitives/io/src/async_externalities.rs
NikVolf Oct 12, 2020
c514e4a
Update primitives/io/src/tasks.rs
NikVolf Oct 12, 2020
e61aee7
Update frame/example-parallel/src/lib.rs
NikVolf Oct 12, 2020
67177c7
fix compilation
NikVolf Oct 12, 2020
9b2570a
Update client/executor/common/src/wasm_runtime.rs
NikVolf Oct 19, 2020
8587edc
address review
NikVolf Oct 19, 2020
00ba286
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Oct 19, 2020
b196d30
Update client/executor/wasmtime/src/instance_wrapper.rs
NikVolf Oct 19, 2020
172e602
Update client/executor/src/native_executor.rs
NikVolf Oct 19, 2020
e5458d2
Update primitives/io/src/tasks.rs
NikVolf Oct 19, 2020
7b1d986
Update client/executor/src/native_executor.rs
NikVolf Oct 19, 2020
14bfbc0
Update primitives/io/src/tasks.rs
NikVolf Oct 19, 2020
2853632
Update client/executor/wasmtime/src/instance_wrapper.rs
NikVolf Oct 19, 2020
7a62626
address some issues
NikVolf Oct 19, 2020
5b10f4b
Merge branch 'nv-parallel-runtime' of github.com:paritytech/substrate…
NikVolf Oct 19, 2020
0583236
address more issues
NikVolf Oct 19, 2020
fd310bd
wasm_only interface
NikVolf Oct 19, 2020
79da04b
Merge remote-tracking branch 'origin/master' into nv-parallel-runtime
NikVolf Oct 19, 2020
6e06f38
define sp_tasks
NikVolf Oct 20, 2020
4080e1a
avoid anyhow
NikVolf Oct 20, 2020
3d1dc8f
fix example
NikVolf Oct 20, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ members = [
"frame/evm",
"frame/example",
"frame/example-offchain-worker",
"frame/example-parallel",
"frame/executive",
"frame/grandpa",
"frame/identity",
Expand Down
19 changes: 19 additions & 0 deletions client/executor/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ pub enum Error {
/// Execution of a host function failed.
#[display(fmt="Host function {} execution failed with: {}", _0, _1)]
FunctionExecution(String, String),
/// No table is present.
///
/// Call was requested that requires table but none was present in the instance.
#[display(fmt="No table exported by wasm blob")]
NoTable,
/// No table entry is present.
///
/// Call was requested that requires specific entry in the table to be present.
#[display(fmt="No table entry with index {} in wasm blob exported table", _0)]
#[from(ignore)]
NoTableEntryWithIndex(u32),
/// Table entry is not a function.
#[display(fmt="Table element with index {} is not a function in wasm blob exported table", _0)]
#[from(ignore)]
TableElementIsNotAFunction(u32),
/// Function in table is null and thus cannot be called.
#[display(fmt="Table entry with index {} in wasm blob is null", _0)]
#[from(ignore)]
FunctionRefIsNull(u32),
}

impl std::error::Error for Error {
Expand Down
57 changes: 55 additions & 2 deletions client/executor/common/src/wasm_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,46 @@
use crate::error::Error;
use sp_wasm_interface::Value;

/// A method to be used to find the entrypoint when calling into the runtime
///
/// Contains variants on how to resolve wasm function that will be invoked.
pub enum InvokeMethod<'a> {
/// Call function exported with this name.
///
/// Located function should have (u32, u32) -> u64 signature.
Export(&'a str),
/// Call a function found in the exported table found under the given index.
///
/// Located function should have (u32, u32) -> u64 signature.
Table(u32),
/// Call function by reference from table through a wrapper.
///
/// Invoked function (`dispatcher_ref`) function
/// should have (u32, u32, u32) -> u64 signature.
///
/// `func` will be passed to the invoked function as a first argument.
cheme marked this conversation as resolved.
Show resolved Hide resolved
TableWithWrapper {
/// Wrapper for the call.
///
/// Function pointer, index into runtime exported table.
dispatcher_ref: u32,
/// Extra argument for dispatch.
///
/// Common usage would be to use it as an actual wasm function pointer
/// that should be invoked, but can be used as any extra argument on the
/// callee side.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this confusing, the docs speak from the "common" case and that it could be used for something different as well. However, the variable name is "func" which already expresses it really strongly what this is.

Either the variable name should be changed or the docs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, I am not entirely sure that those are contradicting:

dispatcher would pass control to some "function" ultimately and I don't think it really matters how that function is dispatched,: a function call into a table or thru a switch, or if the functions are compiled in and from the outside the dispatcher ends up not calling anything.

///
/// This is typically generated and invoked by the runtime itself.
func: u32,
},
NikVolf marked this conversation as resolved.
Show resolved Hide resolved
}

impl<'a> From<&'a str> for InvokeMethod<'a> {
fn from(val: &'a str) -> InvokeMethod<'a> {
InvokeMethod::Export(val)
}
}

/// A trait that defines an abstract WASM runtime module.
///
/// This can be implemented by an execution engine.
Expand All @@ -31,11 +71,24 @@ pub trait WasmModule: Sync + Send {
///
/// This can be implemented by an execution engine.
pub trait WasmInstance: Send {
/// Call a method on this WASM instance and reset it afterwards.
/// Call a method on this WASM instance.
///
/// Before execution, instance is reset.
///
/// Returns the encoded result on success.
fn call(&self, method: InvokeMethod, data: &[u8]) -> Result<Vec<u8>, Error>;

/// Call an exported method on this WASM instance.
///
/// Before execution, instance is reset.
///
/// Returns the encoded result on success.
fn call(&self, method: &str, data: &[u8]) -> Result<Vec<u8>, Error>;
fn call_export(&self, method: &str, data: &[u8]) -> Result<Vec<u8>, Error> {
self.call(method.into(), data)
}

/// Get the value from a global with the given `name`.
///
/// This method is only suitable for getting immutable globals.
fn get_global_const(&self, name: &str) -> Result<Option<Value>, Error>;
}
37 changes: 37 additions & 0 deletions client/executor/runtime-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,43 @@ sp_core::wasm_export_functions! {
assert_ne!(test_message, message_slice);
message_slice.copy_from_slice(test_message);
}

fn test_spawn() {
let data = vec![1u8, 2u8];
let data_new = sp_io::tasks::spawn(tasks::incrementer, data).join();

assert_eq!(data_new, vec![2u8, 3u8]);
}

fn test_nested_spawn() {
let data = vec![7u8, 13u8];
let data_new = sp_io::tasks::spawn(tasks::parallel_incrementer, data).join();

assert_eq!(data_new, vec![10u8, 16u8]);
}

fn test_panic_in_spawned() {
sp_io::tasks::spawn(tasks::panicker, vec![]).join();
}
}

#[cfg(not(feature = "std"))]
mod tasks {
use sp_std::prelude::*;

pub fn incrementer(data: Vec<u8>) -> Vec<u8> {
data.into_iter().map(|v| v + 1).collect()
}

pub fn panicker(_: Vec<u8>) -> Vec<u8> {
panic!()
}

pub fn parallel_incrementer(data: Vec<u8>) -> Vec<u8> {
let first = data.into_iter().map(|v| v + 2).collect::<Vec<_>>();
let second = sp_io::tasks::spawn(incrementer, first).join();
second
}
}

#[cfg(not(feature = "std"))]
Expand Down
60 changes: 54 additions & 6 deletions client/executor/src/integration_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,13 +555,13 @@ fn returns_mutable_static(wasm_method: WasmExecutionMethod) {
).expect("Creates runtime");

let instance = runtime.new_instance().unwrap();
let res = instance.call("returns_mutable_static", &[0]).unwrap();
let res = instance.call_export("returns_mutable_static", &[0]).unwrap();
assert_eq!(33, u64::decode(&mut &res[..]).unwrap());

// We expect that every invocation will need to return the initial
// value plus one. If the value increases more than that then it is
// a sign that the wasm runtime preserves the memory content.
let res = instance.call("returns_mutable_static", &[0]).unwrap();
let res = instance.call_export("returns_mutable_static", &[0]).unwrap();
assert_eq!(33, u64::decode(&mut &res[..]).unwrap());
}

Expand Down Expand Up @@ -590,11 +590,11 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) {
let instance = runtime.new_instance().unwrap();

// On the first invocation we allocate approx. 768KB (75%) of stack and then trap.
let res = instance.call("allocates_huge_stack_array", &true.encode());
let res = instance.call_export("allocates_huge_stack_array", &true.encode());
assert!(res.is_err());

// On the second invocation we allocate yet another 768KB (75%) of stack
let res = instance.call("allocates_huge_stack_array", &false.encode());
let res = instance.call_export("allocates_huge_stack_array", &false.encode());
assert!(res.is_ok());
}

Expand All @@ -616,10 +616,10 @@ fn heap_is_reset_between_calls(wasm_method: WasmExecutionMethod) {
.expect("`__heap_base` is an `i32`");

let params = (heap_base as u32, 512u32 * 64 * 1024).encode();
instance.call("check_and_set_in_heap", &params).unwrap();
instance.call_export("check_and_set_in_heap", &params).unwrap();

// Cal it a second time to check that the heap was freed.
instance.call("check_and_set_in_heap", &params).unwrap();
instance.call_export("check_and_set_in_heap", &params).unwrap();
}

#[test_case(WasmExecutionMethod::Interpreted)]
Expand Down Expand Up @@ -720,3 +720,51 @@ fn wasm_tracing_should_work(wasm_method: WasmExecutionMethod) {
assert_eq!(span_datum.name, "");
assert_eq!(values.bool_values.get("wasm").unwrap(), &true);
}

#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn spawning_runtime_instance_should_work(wasm_method: WasmExecutionMethod) {

let mut ext = TestExternalities::default();
let mut ext = ext.ext();

call_in_wasm(
"test_spawn",
&[],
wasm_method,
&mut ext,
).unwrap();
}

#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn spawning_runtime_instance_nested_should_work(wasm_method: WasmExecutionMethod) {

let mut ext = TestExternalities::default();
let mut ext = ext.ext();

call_in_wasm(
"test_nested_spawn",
&[],
wasm_method,
&mut ext,
).unwrap();
}

#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecutionMethod) {

let mut ext = TestExternalities::default();
let mut ext = ext.ext();

let error_result = call_in_wasm(
"test_panic_in_spawned",
&[],
wasm_method,
&mut ext,
).unwrap_err();

dbg!(&error_result);
assert!(format!("{}", error_result).contains("Spawned task"));
}
Loading