-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Add benchmarks #1660
Add benchmarks #1660
Changes from all commits
94a2845
4a8b081
059a1dc
776532c
e4a4ed2
1b2234a
0cd0f3a
a67011b
b264189
39824b1
59a574b
f1ca383
d7eda3c
148aae2
3d5abbb
a451d59
c28386f
f714e19
85e7765
a03cf77
6ed4828
b539f1f
583c18c
34c70e2
0a464b2
cb365c7
533d53f
310d56a
7667a4d
aa97072
095473f
6330b9d
79e6c18
233e1d0
ec0e0b1
d77b28a
a7d2e92
43cda86
467b474
3e27fdc
5e7eeee
6310b7c
a721747
47bac64
e21ab92
fe874a0
be128e4
7cb74a7
b9454c0
e6a6cb2
ce42e9a
2e02408
bdb68aa
d88da37
07902e0
2b10bd7
34877d1
ce58357
4ef8a80
9d251a6
a1bada4
432b31a
90b8463
b0982f0
92dac2b
6e5adc7
87676ac
1ca3030
58ed9d8
8e6dfdb
19e5180
d61cf21
804fc40
f02e18b
25dda53
69c57cd
f4ace0a
825d3f7
2de9176
dcacfb8
bea47d7
8aaae88
3207302
2a19b8f
e532b7c
6c2cb02
e0ea20b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
#![cfg(feature = "benches")] | ||
#![feature(test)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this file be renamed to perhaps FWIW the spec test suite I don't think is really the most interesting of benchmarks, but at least for our own internal tracking and performance monitoring it probably isn't so bad to track! |
||
|
||
extern crate test; | ||
|
||
use anyhow::{bail, Context as _, Result}; | ||
use std::path::Path; | ||
use wasmtime::{Config, Engine, OptLevel, Store, Strategy}; | ||
use wasmtime_wast::WastContext; | ||
use wast::{ | ||
parser::{self, ParseBuffer}, | ||
Wat, | ||
}; | ||
|
||
macro_rules! mk_test { | ||
($(#[$attrs:meta])* $name:ident, $path:expr, $strategy:expr) => { | ||
mod $name { | ||
use wasmtime::Strategy; | ||
|
||
#[bench] | ||
$(#[$attrs])* | ||
fn compile(b: &mut ::test::bench::Bencher) { | ||
crate::bench_compile(b, $path, $strategy).unwrap(); | ||
} | ||
|
||
#[bench] | ||
$(#[$attrs])* | ||
fn run(b: &mut ::test::bench::Bencher) { | ||
crate::bench_run(b, $path, $strategy).unwrap(); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
include!(concat!(env!("OUT_DIR"), "/wast_testsuite_tests.rs")); | ||
|
||
fn bench_compile(b: &mut test::bench::Bencher, wast: &str, strategy: Strategy) -> Result<()> { | ||
let path = Path::new(wast); | ||
|
||
let simd = path.iter().any(|s| s == "simd"); | ||
|
||
let bulk_mem = path.iter().any(|s| s == "bulk-memory-operations"); | ||
|
||
// Some simd tests assume support for multiple tables, which are introduced | ||
// by reference types. | ||
let reftypes = simd || path.iter().any(|s| s == "reference-types"); | ||
|
||
let multi_val = path.iter().any(|s| s == "multi-value"); | ||
|
||
let mut cfg = Config::new(); | ||
cfg.wasm_simd(simd) | ||
.wasm_bulk_memory(bulk_mem) | ||
.wasm_reference_types(reftypes) | ||
.wasm_multi_value(multi_val) | ||
.strategy(strategy)? | ||
.cranelift_debug_verifier(cfg!(debug_assertions)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This I think is duplicated with the testing code as well as with the function below, could this all be consolidated into one function, perhaps in the |
||
|
||
// FIXME: https://github.com/bytecodealliance/wasmtime/issues/1186 | ||
if simd { | ||
cfg.cranelift_opt_level(OptLevel::None); | ||
} | ||
|
||
let store = Store::new(&Engine::new(&cfg)); | ||
let mut wast_context = WastContext::new(store); | ||
wast_context.register_spectest()?; | ||
|
||
let adjust_wast = |mut err: wast::Error| { | ||
err.set_path(path); | ||
err.set_text(wast); | ||
err | ||
}; | ||
|
||
let file_contents = std::fs::read_to_string(path) | ||
.with_context(|| format!("failed to read `{}`", path.display()))?; | ||
let buf = ParseBuffer::new(&file_contents).map_err(adjust_wast)?; | ||
let ast = parser::parse::<wast::Wast>(&buf).map_err(adjust_wast)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be deduplicated with the |
||
|
||
let mut modules = Vec::new(); | ||
|
||
for directive in ast.directives { | ||
use wast::WastDirective::*; | ||
|
||
match directive { | ||
Module(mut module) => { | ||
let binary = module.encode()?; | ||
|
||
wast_context.module( | ||
module.id.map(|s| &s.name()[..]).as_ref().map(|s| &s[..]), | ||
&binary, | ||
)?; | ||
|
||
b.bytes += binary.len() as u64; | ||
modules.push(binary); | ||
} | ||
QuoteModule { span: _, source } => { | ||
let mut module = String::new(); | ||
for src in source { | ||
module.push_str(std::str::from_utf8(src)?); | ||
module.push_str(" "); | ||
} | ||
let buf = ParseBuffer::new(&module)?; | ||
let mut wat = parser::parse::<Wat>(&buf)?; | ||
let binary = wat.module.encode()?; | ||
wast_context.module( | ||
wat.module | ||
.id | ||
.map(|s| &s.name()[..]) | ||
.as_ref() | ||
.map(|s| &s[..]), | ||
&binary, | ||
)?; | ||
|
||
b.bytes += binary.len() as u64; | ||
modules.push(binary); | ||
} | ||
Register { | ||
span: _, | ||
name, | ||
module, | ||
} => { | ||
wast_context.register(module.map(|s| s.name()), name)?; | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
b.iter(|| { | ||
for bin in &modules { | ||
wast_context.instantiate(bin).unwrap(); | ||
} | ||
}); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn bench_run(b: &mut test::bench::Bencher, wast: &str, strategy: Strategy) -> Result<()> { | ||
let path = Path::new(wast); | ||
|
||
let simd = path.iter().any(|s| s == "simd"); | ||
|
||
let bulk_mem = path.iter().any(|s| s == "bulk-memory-operations"); | ||
|
||
// Some simd tests assume support for multiple tables, which are introduced | ||
// by reference types. | ||
let reftypes = simd || path.iter().any(|s| s == "reference-types"); | ||
|
||
let multi_val = path.iter().any(|s| s == "multi-value"); | ||
|
||
let mut cfg = Config::new(); | ||
cfg.wasm_simd(simd) | ||
.wasm_bulk_memory(bulk_mem) | ||
.wasm_reference_types(reftypes) | ||
.wasm_multi_value(multi_val) | ||
.strategy(strategy)? | ||
.cranelift_debug_verifier(cfg!(debug_assertions)); | ||
|
||
// FIXME: https://github.com/bytecodealliance/wasmtime/issues/1186 | ||
if simd { | ||
cfg.cranelift_opt_level(OptLevel::None); | ||
} | ||
|
||
let store = Store::new(&Engine::new(&cfg)); | ||
let mut wast_context = WastContext::new(store); | ||
wast_context.register_spectest()?; | ||
|
||
let adjust_wast = |mut err: wast::Error| { | ||
err.set_path(path); | ||
err.set_text(wast); | ||
err | ||
}; | ||
|
||
let file_contents = std::fs::read_to_string(path) | ||
.with_context(|| format!("failed to read `{}`", path.display()))?; | ||
let buf = ParseBuffer::new(&file_contents).map_err(adjust_wast)?; | ||
let ast = parser::parse::<wast::Wast>(&buf).map_err(adjust_wast)?; | ||
|
||
let mut execute_directives = Vec::new(); | ||
let mut current = None; | ||
let mut dummy_name_id = 0; | ||
|
||
for directive in ast.directives { | ||
use wast::{WastDirective::*, WastExecute}; | ||
|
||
match directive { | ||
Module(mut module) => { | ||
let binary = module.encode()?; | ||
|
||
let name = module.id.map(|s| s.name().to_string()).unwrap_or_else(|| { | ||
let name = format!("---dummy-name-{}", dummy_name_id); | ||
dummy_name_id += 1; | ||
name | ||
}); | ||
wast_context.module(Some(&name), &binary)?; | ||
current = Some(name); | ||
} | ||
QuoteModule { span: _, source } => { | ||
let mut module = String::new(); | ||
for src in source { | ||
module.push_str(std::str::from_utf8(src)?); | ||
module.push_str(" "); | ||
} | ||
let buf = ParseBuffer::new(&module)?; | ||
let mut wat = parser::parse::<Wat>(&buf)?; | ||
let binary = wat.module.encode()?; | ||
let name = wat | ||
.module | ||
.id | ||
.map(|s| s.name().to_string()) | ||
.unwrap_or_else(|| { | ||
let name = format!("---dummy-name-{}", dummy_name_id); | ||
dummy_name_id += 1; | ||
name | ||
}); | ||
wast_context.module(Some(&name), &binary)?; | ||
current = Some(name); | ||
} | ||
Register { | ||
span: _, | ||
name, | ||
module, | ||
} => { | ||
wast_context.register(module.map(|s| s.name()), name)?; | ||
} | ||
Invoke(call) | ||
| AssertExhaustion { call, .. } | ||
| AssertReturn { | ||
exec: WastExecute::Invoke(call), | ||
.. | ||
} | ||
| AssertTrap { | ||
exec: WastExecute::Invoke(call), | ||
.. | ||
} => { | ||
use wasmtime::Val; | ||
|
||
// Copy/pasted from `wasmtime-wast` | ||
fn runtime_value(v: &wast::Expression<'_>) -> Result<Val> { | ||
use wast::Instruction::*; | ||
|
||
if v.instrs.len() != 1 { | ||
bail!("too many instructions in {:?}", v); | ||
} | ||
Ok(match &v.instrs[0] { | ||
I32Const(x) => Val::I32(*x), | ||
I64Const(x) => Val::I64(*x), | ||
F32Const(x) => Val::F32(x.bits), | ||
F64Const(x) => Val::F64(x.bits), | ||
V128Const(x) => Val::V128(u128::from_le_bytes(x.to_le_bytes())), | ||
other => bail!("couldn't convert {:?} to a runtime value", other), | ||
}) | ||
} | ||
|
||
let values = call | ||
.args | ||
.iter() | ||
.map(runtime_value) | ||
.collect::<Result<Vec<_>>>()?; | ||
|
||
execute_directives.push(( | ||
call.module | ||
.map(|m| m.name().to_string()) | ||
.unwrap_or_else(|| current.clone().unwrap()), | ||
call.name.to_string(), | ||
values, | ||
)); | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
b.iter(|| { | ||
for (mod_name, fn_name, args) in &execute_directives { | ||
wast_context.invoke(Some(mod_name), fn_name, args).unwrap(); | ||
} | ||
}); | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to use a hand-rolled
harness = false
scheme or something likecriterion
that works on stable?