Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasm interp speedup #4707

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 8 additions & 4 deletions crates/compiler/builtins/bitcode/run-wasm-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ set -euxo pipefail
# Test failures will always point at the _start function
# Make sure to look at the rest of the stack trace!

# Zig will try to run the test binary it produced, but it is a wasm object and hence your OS won't
# know how to run it. In the error message, it prints the binary it tried to run. We use some fun
# unix tools to get that path, then feed it to wasmer
zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd wasmer --test-cmd-bin
# Zig will try to run the test binary it produced, but since your OS doesn't know how to
# run Wasm binaries natively, we need to provide a Wasm interpreter as a "test command".
zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd ~/roc/target/release/roc_wasm_interp --test-cmd-bin

hyperfine --warmup 1 \
'zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd wasmer --test-cmd-bin' \
'zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd wasm3 --test-cmd-bin' \
'zig test -target wasm32-wasi-musl -O ReleaseFast src/main.zig --test-cmd ~/roc/target/release/roc_wasm_interp --test-cmd-bin'
174 changes: 87 additions & 87 deletions crates/wasm_interp/src/call_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,93 +197,93 @@ impl<'a> CallStack<'a> {
pc: usize,
buffer: &mut String,
) -> fmt::Result {
let divider = "-------------------";
writeln!(buffer, "{}", divider)?;

let mut value_stack_iter = value_stack.iter();

for frame in 0..self.frame_offsets.len() {
let next_frame = frame + 1;
let op_offset = if next_frame < self.frame_offsets.len() {
// return address of next frame = next op in this frame
let next_op = self.return_addrs_and_block_depths[next_frame].0 as usize;
// Call address is more intuitive than the return address when debugging. Search backward for it.
// Skip last byte of function index to avoid a false match with CALL/CALLINDIRECT.
// The more significant bytes won't match because of LEB-128 encoding.
let mut call_op = next_op - 2;
loop {
let byte = module.code.bytes[call_op];
if byte == OpCode::CALL as u8 || byte == OpCode::CALLINDIRECT as u8 {
break;
} else {
call_op -= 1;
}
}
call_op
} else {
pc
};

let fn_index = pc_to_fn_index(op_offset, module);
let address = op_offset + module.code.section_offset as usize;
writeln!(buffer, "function {}", fn_index)?;
writeln!(buffer, " address {:06x}", address)?; // format matches wasm-objdump, for easy search

write!(buffer, " args ")?;
let arg_count = {
let n_import_fns = module.import.imports.len();
let signature_index = if fn_index < n_import_fns {
match module.import.imports[fn_index].description {
ImportDesc::Func { signature_index } => signature_index,
_ => unreachable!(),
}
} else {
module.function.signatures[fn_index - n_import_fns]
};
module.types.look_up_arg_type_bytes(signature_index).len()
};
let args_and_locals_count = {
let frame_offset = self.frame_offsets[frame] as usize;
let next_frame_offset = if frame == self.frame_offsets.len() - 1 {
self.locals_data.len()
} else {
self.frame_offsets[frame + 1] as usize
};
next_frame_offset - frame_offset
};
for index in 0..args_and_locals_count {
let value = self.get_local_help(frame, index as u32);
if index != 0 {
write!(buffer, ", ")?;
}
if index == arg_count {
write!(buffer, "\n locals ")?;
}
write!(buffer, "{}: {:?}", index, value)?;
}
write!(buffer, "\n stack [")?;

let frame_value_count = {
let value_stack_base = self.value_stack_bases[frame];
let next_value_stack_base = if frame == self.frame_offsets.len() - 1 {
value_stack.len() as u32
} else {
self.value_stack_bases[frame + 1]
};
next_value_stack_base - value_stack_base
};
for i in 0..frame_value_count {
if i != 0 {
write!(buffer, ", ")?;
}
if let Some(value) = value_stack_iter.next() {
write!(buffer, "{:?}", value)?;
}
}

writeln!(buffer, "]")?;
writeln!(buffer, "{}", divider)?;
}
// let divider = "-------------------";
// writeln!(buffer, "{}", divider)?;

// let mut value_stack_iter = value_stack.iter();

// for frame in 0..self.frame_offsets.len() {
// let next_frame = frame + 1;
// let op_offset = if next_frame < self.frame_offsets.len() {
// // return address of next frame = next op in this frame
// let next_op = self.return_addrs_and_block_depths[next_frame].0 as usize;
// // Call address is more intuitive than the return address when debugging. Search backward for it.
// // Skip last byte of function index to avoid a false match with CALL/CALLINDIRECT.
// // The more significant bytes won't match because of LEB-128 encoding.
// let mut call_op = next_op - 2;
// loop {
// let byte = module.code.bytes[call_op];
// if byte == OpCode::CALL as u8 || byte == OpCode::CALLINDIRECT as u8 {
// break;
// } else {
// call_op -= 1;
// }
// }
// call_op
// } else {
// pc
// };

// let fn_index = pc_to_fn_index(op_offset, module);
// let address = op_offset + module.code.section_offset as usize;
// writeln!(buffer, "function {}", fn_index)?;
// writeln!(buffer, " address {:06x}", address)?; // format matches wasm-objdump, for easy search

// write!(buffer, " args ")?;
// let arg_count = {
// let n_import_fns = module.import.imports.len();
// let signature_index = if fn_index < n_import_fns {
// match module.import.imports[fn_index].description {
// ImportDesc::Func { signature_index } => signature_index,
// _ => unreachable!(),
// }
// } else {
// module.function.signatures[fn_index - n_import_fns]
// };
// module.types.look_up_arg_type_bytes(signature_index).len()
// };
// let args_and_locals_count = {
// let frame_offset = self.frame_offsets[frame] as usize;
// let next_frame_offset = if frame == self.frame_offsets.len() - 1 {
// self.locals_data.len()
// } else {
// self.frame_offsets[frame + 1] as usize
// };
// next_frame_offset - frame_offset
// };
// for index in 0..args_and_locals_count {
// let value = self.get_local_help(frame, index as u32);
// if index != 0 {
// write!(buffer, ", ")?;
// }
// if index == arg_count {
// write!(buffer, "\n locals ")?;
// }
// write!(buffer, "{}: {:?}", index, value)?;
// }
// write!(buffer, "\n stack [")?;

// let frame_value_count = {
// let value_stack_base = self.value_stack_bases[frame];
// let next_value_stack_base = if frame == self.frame_offsets.len() - 1 {
// value_stack.len() as u32
// } else {
// self.value_stack_bases[frame + 1]
// };
// next_value_stack_base - value_stack_base
// };
// for i in 0..frame_value_count {
// if i != 0 {
// write!(buffer, ", ")?;
// }
// if let Some(value) = value_stack_iter.next() {
// write!(buffer, "{:?}", value)?;
// }
// }

// writeln!(buffer, "]")?;
// writeln!(buffer, "{}", divider)?;
// }

Ok(())
}
Expand Down
28 changes: 14 additions & 14 deletions crates/wasm_interp/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use roc_wasm_module::{Value, ValueType};

use crate::call_stack::CallStack;
use crate::value_stack::ValueStack;
use crate::{pc_to_fn_index, Error, ImportDispatcher};
use crate::{Error, ImportDispatcher};

pub enum Action {
Continue,
Expand Down Expand Up @@ -451,7 +451,7 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
}

let mut action = Action::Continue;
let mut implicit_return = false;
// let mut implicit_return = false;

match op_code {
UNREACHABLE => {
Expand Down Expand Up @@ -503,7 +503,7 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
if self.block_loop_addrs.len() == self.outermost_block as usize {
// implicit RETURN at end of function
action = self.do_return();
implicit_return = true;
// implicit_return = true;
} else {
self.block_loop_addrs.pop().unwrap();
}
Expand Down Expand Up @@ -1504,17 +1504,17 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
}
}

if let Some(debug_string) = &self.debug_string {
let base = self.call_stack.value_stack_base();
let slice = self.value_stack.get_slice(base as usize);
eprintln!("{:06x} {:17} {:?}", file_offset, debug_string, slice);
if op_code == RETURN || (op_code == END && implicit_return) {
let fn_index = pc_to_fn_index(self.program_counter, module);
eprintln!("returning to function {}\n", fn_index);
} else if op_code == CALL || op_code == CALLINDIRECT {
eprintln!();
}
}
// if let Some(debug_string) = &self.debug_string {
// let base = self.call_stack.value_stack_base();
// let slice = self.value_stack.get_slice(base as usize);
// eprintln!("{:06x} {:17} {:?}", file_offset, debug_string, slice);
// if op_code == RETURN || (op_code == END && implicit_return) {
// let fn_index = pc_to_fn_index(self.program_counter, module);
// eprintln!("returning to function {}\n", fn_index);
// } else if op_code == CALL || op_code == CALLINDIRECT {
// eprintln!();
// }
// }

Ok(action)
}
Expand Down
35 changes: 19 additions & 16 deletions crates/wasm_interp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,26 @@ fn main() -> io::Result<()> {
});

// Run

let result = inst.call_export_from_cli(&module, start_fn_name, &wasi_argv);

// Print out return value, if any

match result {
Ok(Some(val)) => {
if is_hex_format {
println!("{:#x?}", val)
} else {
println!("{:?}", val)
// let end= 10000;
let end = 1;
for _ in 0..end {
let result = inst.call_export_from_cli(&module, start_fn_name, &wasi_argv);

// Print out return value, if any

match result {
Ok(Some(val)) => {
if is_hex_format {
println!("{:#x?}", val)
} else {
println!("{:?}", val)
}
}
Ok(None) => {}
Err(e) => {
eprintln!("{}", e);
process::exit(3);
}
}
Ok(None) => {}
Err(e) => {
eprintln!("{}", e);
process::exit(3);
}
}

Expand Down
Loading