Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/benches/trap.rs
1685 views
1
use anyhow::Result;
2
use criterion::*;
3
use wasmtime::*;
4
5
criterion_main!(benches);
6
criterion_group!(benches, bench_traps);
7
8
fn bench_traps(c: &mut Criterion) {
9
bench_multi_threaded_traps(c);
10
bench_many_modules_registered_traps(c);
11
bench_many_stack_frames_traps(c);
12
bench_host_wasm_frames_traps(c);
13
}
14
15
fn bench_multi_threaded_traps(c: &mut Criterion) {
16
let mut group = c.benchmark_group("multi-threaded-traps");
17
18
for num_bg_threads in vec![0, 1, 2, 4, 8, 16] {
19
group.throughput(Throughput::Elements(num_bg_threads));
20
group.bench_with_input(
21
BenchmarkId::from_parameter(num_bg_threads),
22
&num_bg_threads,
23
|b, &num_bg_threads| {
24
let engine = Engine::default();
25
let module = module(&engine, 10).unwrap();
26
27
b.iter_custom(|iters| {
28
let (started_sender, started_receiver) = std::sync::mpsc::channel();
29
30
// Spawn threads in the background doing infinite work.
31
let threads = (0..num_bg_threads)
32
.map(|_| {
33
let (done_sender, done_receiver) = std::sync::mpsc::channel();
34
let handle = std::thread::spawn({
35
let engine = engine.clone();
36
let module = module.clone();
37
let started_sender = started_sender.clone();
38
move || {
39
let mut store = Store::new(&engine, ());
40
let instance = Instance::new(&mut store, &module, &[]).unwrap();
41
let f =
42
instance.get_typed_func::<(), ()>(&mut store, "").unwrap();
43
44
// Notify the parent thread that we are
45
// doing background work now.
46
started_sender.send(()).unwrap();
47
48
// Keep doing background work until the
49
// parent tells us to stop.
50
loop {
51
if let Ok(()) = done_receiver.try_recv() {
52
return;
53
}
54
assert!(f.call(&mut store, ()).is_err());
55
}
56
}
57
});
58
(handle, done_sender)
59
})
60
.collect::<Vec<_>>();
61
62
// Wait on all the threads to start up.
63
for _ in 0..num_bg_threads {
64
let _ = started_receiver.recv().unwrap();
65
}
66
67
let mut store = Store::new(&engine, ());
68
let instance = Instance::new(&mut store, &module, &[]).unwrap();
69
let f = instance.get_typed_func::<(), ()>(&mut store, "").unwrap();
70
71
// Measure how long it takes to do `iters` worth of traps
72
// while there is a bunch of background work going on.
73
let start = std::time::Instant::now();
74
for _ in 0..iters {
75
assert!(f.call(&mut store, ()).is_err());
76
}
77
let elapsed = start.elapsed();
78
79
// Clean up all of our background threads.
80
threads.into_iter().for_each(|(handle, done_sender)| {
81
done_sender.send(()).unwrap();
82
handle.join().unwrap();
83
});
84
85
elapsed
86
});
87
},
88
);
89
}
90
91
group.finish();
92
}
93
94
fn bench_many_modules_registered_traps(c: &mut Criterion) {
95
let mut group = c.benchmark_group("many-modules-registered-traps");
96
97
for num_modules in vec![1, 8, 64, 512, 4096] {
98
group.throughput(Throughput::Elements(num_modules));
99
group.bench_with_input(
100
BenchmarkId::from_parameter(num_modules),
101
&num_modules,
102
|b, &num_modules| {
103
let engine = Engine::default();
104
let modules = (0..num_modules)
105
.map(|_| module(&engine, 10).unwrap())
106
.collect::<Vec<_>>();
107
108
b.iter_custom(|iters| {
109
let mut store = Store::new(&engine, ());
110
let instance = Instance::new(&mut store, modules.last().unwrap(), &[]).unwrap();
111
let f = instance.get_typed_func::<(), ()>(&mut store, "").unwrap();
112
113
let start = std::time::Instant::now();
114
for _ in 0..iters {
115
assert!(f.call(&mut store, ()).is_err());
116
}
117
start.elapsed()
118
});
119
},
120
);
121
}
122
123
group.finish()
124
}
125
126
fn bench_many_stack_frames_traps(c: &mut Criterion) {
127
let mut group = c.benchmark_group("many-stack-frames-traps");
128
129
for num_stack_frames in vec![1, 8, 64, 512] {
130
group.throughput(Throughput::Elements(num_stack_frames));
131
group.bench_with_input(
132
BenchmarkId::from_parameter(num_stack_frames),
133
&num_stack_frames,
134
|b, &num_stack_frames| {
135
let engine = Engine::default();
136
let module = module(&engine, num_stack_frames).unwrap();
137
138
b.iter_custom(|iters| {
139
let mut store = Store::new(&engine, ());
140
let instance = Instance::new(&mut store, &module, &[]).unwrap();
141
let f = instance.get_typed_func::<(), ()>(&mut store, "").unwrap();
142
143
let start = std::time::Instant::now();
144
for _ in 0..iters {
145
assert!(f.call(&mut store, ()).is_err());
146
}
147
start.elapsed()
148
});
149
},
150
);
151
}
152
153
group.finish()
154
}
155
156
fn bench_host_wasm_frames_traps(c: &mut Criterion) {
157
let mut group = c.benchmark_group("host-wasm-frames-traps");
158
159
let wat = r#"
160
(module
161
(import "" "" (func $host_func (param i32)))
162
(func (export "f") (param i32)
163
local.get 0
164
i32.eqz
165
if
166
unreachable
167
end
168
169
local.get 0
170
i32.const 1
171
i32.sub
172
call $host_func
173
)
174
)
175
"#;
176
177
let engine = Engine::default();
178
let module = Module::new(&engine, wat).unwrap();
179
180
for num_stack_frames in vec![20, 40, 60, 80, 100, 120, 140, 160, 180, 200] {
181
group.throughput(Throughput::Elements(num_stack_frames));
182
group.bench_with_input(
183
BenchmarkId::from_parameter(num_stack_frames),
184
&num_stack_frames,
185
|b, &num_stack_frames| {
186
b.iter_custom(|iters| {
187
let mut store = Store::new(&engine, ());
188
let host_func = Func::new(
189
&mut store,
190
FuncType::new(&engine, vec![ValType::I32], vec![]),
191
|mut caller, args, _results| {
192
let f = caller.get_export("f").unwrap();
193
let f = f.into_func().unwrap();
194
f.call(caller, args, &mut [])?;
195
Ok(())
196
},
197
);
198
let instance = Instance::new(&mut store, &module, &[host_func.into()]).unwrap();
199
let f = instance
200
.get_typed_func::<(i32,), ()>(&mut store, "f")
201
.unwrap();
202
203
let start = std::time::Instant::now();
204
for _ in 0..iters {
205
assert!(f.call(&mut store, (num_stack_frames as i32,)).is_err());
206
}
207
start.elapsed()
208
});
209
},
210
);
211
}
212
213
group.finish()
214
}
215
216
fn module(engine: &Engine, num_funcs: u64) -> Result<Module> {
217
let mut wat = String::new();
218
wat.push_str("(module\n");
219
for i in 0..num_funcs {
220
let j = i + 1;
221
wat.push_str(&format!("(func $f{i} call $f{j})\n"));
222
}
223
wat.push_str(&format!("(func $f{num_funcs} unreachable)\n"));
224
wat.push_str(&format!("(export \"\" (func $f0))\n"));
225
wat.push_str(")\n");
226
227
Module::new(engine, &wat)
228
}
229
230