Skip to content

Commit

Permalink
Merge #835
Browse files Browse the repository at this point in the history
835: Add parallel execution example r=Hywan a=MarkMcCaskey

A bit wip

# Review

- [x] Add a short description of the the change to the CHANGELOG.md file


Co-authored-by: Mark McCaskey <[email protected]>
  • Loading branch information
bors[bot] and Mark McCaskey authored Sep 27, 2019
2 parents 287b425 + 1083e7c commit 7313714
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 1 deletion.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ Blocks of changes will separated by version increments.

## **[Unreleased]**

- [#835](https://github.com/wasmerio/wasmer/pull/836) Update Cranelift fork version to `0.44.0`
- [#836](https://github.com/wasmerio/wasmer/pull/836) Update Cranelift fork version to `0.44.0`
- [#839](https://github.com/wasmerio/wasmer/pull/839) Change supported version to stable Rust 1.37+
- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when unwraping `wasmer` arguments
- [#835](https://github.com/wasmerio/wasmer/pull/835) Add parallel execution example (independent instances created from the same `ImportObject` and `Module` run with rayon)
- [#834](https://github.com/wasmerio/wasmer/pull/834) Fix panic when parsing numerical arguments for no-ABI targets run with the wasmer binary
- [#833](https://github.com/wasmerio/wasmer/pull/833) Add doc example of using ImportObject's new `maybe_with_namespace` method
- [#832](https://github.com/wasmerio/wasmer/pull/832) Delete unused runtime ABI
- [#809](https://github.com/wasmerio/wasmer/pull/809) Fix bugs leading to panics in `LocalBacking`.
Expand Down
24 changes: 24 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ members = [
"lib/emscripten-tests",
"lib/middleware-common-tests",
"examples/plugin-for-example",
"examples/parallel",
"examples/parallel-guest",
]

[build-dependencies]
Expand Down
Binary file added examples/parallel-guest.wasm
Binary file not shown.
11 changes: 11 additions & 0 deletions examples/parallel-guest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "parallel-guest"
version = "0.1.0"
authors = ["The Wasmer Engineering Team <[email protected]>"]
license = "MIT"
edition = "2018"
publish = false

[dependencies]
md5 = "0.6"
lazy_static = "1"
82 changes: 82 additions & 0 deletions examples/parallel-guest/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#[macro_use]
extern crate lazy_static;

extern "C" {
fn get_hashed_password(ptr: u32, len: u32) -> u32;
fn print_char(c: u32);
}

fn print_str(s: &str) {
for c in s.chars() {
unsafe { print_char(c as u32) };
}
unsafe { print_char(b'\n' as u32) };
}

fn load_hashed_password() -> Option<String> {
let mut buffer = String::with_capacity(32);
for _ in 0..32 {
buffer.push(0 as char);
}
let result =
unsafe { get_hashed_password(buffer.as_mut_ptr() as u32, buffer.capacity() as u32) };

if result == 0 {
Some(buffer)
} else {
None
}
}

lazy_static! {
static ref HASHED_PASSWORD: String = load_hashed_password().unwrap();
}

static PASSWORD_CHARS: &'static [u8] = b"abcdefghijklmnopqrstuvwxyz0123456789";

// for simplicty we define a scheme for mapping numbers onto passwords
fn num_to_password(mut num: u64) -> String {
let mut extra_zero = num == 0;
let mut out = String::new();
while num > 0 {
out.push(PASSWORD_CHARS[num as usize % PASSWORD_CHARS.len()] as char);
extra_zero = extra_zero || num == PASSWORD_CHARS.len() as u64;
num /= PASSWORD_CHARS.len() as u64;
}

if extra_zero {
out.push(PASSWORD_CHARS[0] as char);
}

out
}

#[repr(C)]
struct RetStr {
ptr: u32,
len: u32,
}

// returns a (pointer, len) to the password or null
#[no_mangle]
fn check_password(from: u64, to: u64) -> u64 {
for i in from..to {
let password = num_to_password(i);
let digest = md5::compute(&password);

let hash_as_str = format!("{:x}", digest);
if hash_as_str == *HASHED_PASSWORD {
let ret = RetStr {
ptr: password.as_ptr() as usize as u32,
len: password.len() as u32,
};
// leak the data so ending the function doesn't corrupt it, if we cared the host could free it after
std::mem::forget(password);
return unsafe { std::mem::transmute(ret) };
}
}

return 0;
}

fn main() {}
14 changes: 14 additions & 0 deletions examples/parallel/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "parallel"
version = "0.1.0"
authors = ["The Wasmer Engineering Team <[email protected]>"]
edition = "2018"
repository = "https://github.com/wasmerio/wasmer"
publish = false
license = "MIT"

[dependencies]
rayon = "1.2"
time = "0.1"
wasmer-runtime = { path = "../../lib/runtime" }
wasmer-runtime-core = { path = "../../lib/runtime-core" }
5 changes: 5 additions & 0 deletions examples/parallel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Parallel Wasmer example

This example shows executing independent code from multiple threads on an "embarassingly parallel" problem

This is a toy example of cracking md5 hashes. This is not a benchmark. This example is not optimized, it will compare poorly to an implementation that is.
137 changes: 137 additions & 0 deletions examples/parallel/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use rayon::prelude::*;
use wasmer_runtime::{compile_with, compiler_for_backend, func, imports, instantiate, Backend};
use wasmer_runtime_core::{
memory::ptr::{Array, WasmPtr},
vm::Ctx,
};

static PLUGIN_LOCATION: &'static str = "../parallel-guest.wasm";

fn get_hashed_password(ctx: &mut Ctx, ptr: WasmPtr<u8, Array>, len: u32) -> u32 {
// "hard" password - 7 characters
//let password = b"2ab96390c7dbe3439de74d0c9b0b1767";
// "easy" password - 5 characters
let password = b"ab56b4d92b40713acc5af89985d4b786";
let memory = ctx.memory(0);
if let Some(writer) = ptr.deref(memory, 0, len) {
for (i, byte) in password.iter().enumerate() {
writer[i].set(*byte)
}

0
} else {
u32::max_value()
}
}

#[repr(C)]
struct RetStr {
ptr: u32,
len: u32,
}

fn print_char(_cxt: &mut Ctx, c: u32) {
print!("{}", c as u8 as char);
}

fn main() {
let wasm_bytes = std::fs::read(PLUGIN_LOCATION).expect(&format!(
"Could not read in WASM plugin at {}",
PLUGIN_LOCATION
));

let imports = imports! {
"env" => {
"get_hashed_password" => func!(get_hashed_password),
"print_char" => func!(print_char),
},
};
let compiler = compiler_for_backend(Backend::default()).unwrap();
let module = compile_with(&wasm_bytes[..], compiler.as_ref()).unwrap();

println!("Parallel");
let start_ts = time::SteadyTime::now();
for outer in 0..1000u64 {
let start = outer * 1000;
let end = start + 1000;
let out = (start..=end)
.into_par_iter()
.filter_map(|i| {
let instance = module
.clone()
.instantiate(&imports)
.expect("failed to instantiate wasm module");
let check_password = instance.func::<(u64, u64), u64>("check_password").unwrap();
let j = i * 10000;
let result = check_password.call(j, j + 10000).unwrap();
print!(".");
use std::io::Write;
std::io::stdout().flush().unwrap();
if result != 0 {
let res: RetStr = unsafe { std::mem::transmute(result) };

let ctx = instance.context();
let memory = ctx.memory(0);
let wasm_ptr: WasmPtr<u8, Array> = WasmPtr::new(res.ptr);
let password_str = wasm_ptr
.get_utf8_string(memory, res.len)
.unwrap()
.to_string();
Some(password_str)
} else {
None
}
})
.find_first(|_: &String| true);
if out.is_some() {
let end_ts = time::SteadyTime::now();
let delta = end_ts - start_ts;
println!(
"Password cracked: \"{}\" in {}.{:03}",
out.unwrap(),
delta.num_seconds(),
(delta.num_milliseconds() % 1000),
);
break;
}
}

println!("Serial:");
let start_ts = time::SteadyTime::now();
let instance =
instantiate(&wasm_bytes[..], &imports).expect("failed to instantiate wasm module");

let check_password = instance.func::<(u64, u64), u64>("check_password").unwrap();

let mut out: Option<RetStr> = None;
for i in (0..=u64::max_value()).step_by(10000) {
let result = check_password.call(i, i + 10000).unwrap();
print!(".");
use std::io::Write;
std::io::stdout().flush().unwrap();
if result != 0 {
out = Some(unsafe { std::mem::transmute(result) });
break;
}
}
println!("");

if let Some(res) = out {
let ctx = instance.context();
let memory = ctx.memory(0);
let wasm_ptr: WasmPtr<u8, Array> = WasmPtr::new(res.ptr);

let password_str = wasm_ptr.get_utf8_string(memory, res.len).unwrap();

let end_ts = time::SteadyTime::now();
let delta = end_ts - start_ts;
println!(
"Password cracked: \"{}\" in {}.{:03}",
password_str,
delta.num_seconds(),
(delta.num_milliseconds() % 1000),
);
} else {
println!("Password not found!");
}
}

0 comments on commit 7313714

Please sign in to comment.