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