Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/fast_instantiation.rs
1685 views
1
//! Tuning Wasmtime for fast instantiation.
2
3
use anyhow::anyhow;
4
use wasmtime::{
5
Config, Engine, InstanceAllocationStrategy, Linker, Module, PoolingAllocationConfig, Result,
6
Store,
7
};
8
9
fn main() -> Result<()> {
10
let mut config = Config::new();
11
12
// Configure and enable the pooling allocator with space for 100 memories of
13
// up to 2GiB in size, 100 tables holding up to 5000 elements, and with a
14
// limit of no more than 100 concurrent instances.
15
let mut pool = PoolingAllocationConfig::new();
16
pool.total_memories(100);
17
pool.max_memory_size(1 << 31); // 2 GiB
18
pool.total_tables(100);
19
pool.table_elements(5000);
20
pool.total_core_instances(100);
21
config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool));
22
23
// Enable copy-on-write heap images.
24
config.memory_init_cow(true);
25
26
// Create an engine with our configuration.
27
let engine = Engine::new(&config)?;
28
29
// Create a linker and populate it with all the imports needed for the Wasm
30
// programs we will run. In a more realistic Wasmtime embedding, this would
31
// probably involve adding WASI functions to the linker, for example.
32
let mut linker = Linker::<()>::new(&engine);
33
linker.func_wrap("math", "add", |a: u32, b: u32| -> u32 { a + b })?;
34
35
// Create a new module, load a pre-compiled module from disk, or etc...
36
let module = Module::new(
37
&engine,
38
r#"
39
(module
40
(import "math" "add" (func $add (param i32 i32) (result i32)))
41
(func (export "run")
42
(call $add (i32.const 29) (i32.const 13))
43
)
44
)
45
"#,
46
)?;
47
48
// Create an `InstancePre` for our module, doing import resolution and
49
// type-checking ahead-of-time and removing it from the instantiation
50
// critical path.
51
let instance_pre = linker.instantiate_pre(&module)?;
52
53
// Now we can very quickly instantiate our module, so long as we have no
54
// more than 100 concurrent instances at a time!
55
//
56
// For example, we can spawn 100 threads and have each of them instantiate
57
// and run our Wasm module in a loop.
58
//
59
// In a real Wasmtime embedding, this would be doing something like handling
60
// new HTTP requests, game events, or etc... instead of just calling the
61
// same function. A production embedding would likely also be using async,
62
// in which case it would want some sort of back-pressure mechanism (like a
63
// semaphore) on incoming tasks to avoid attempting to allocate more than
64
// the pool's maximum-supported concurrent instances (at which point,
65
// instantiation will start returning errors).
66
let handles: Vec<std::thread::JoinHandle<Result<()>>> = (0..100)
67
.map(|_| {
68
let engine = engine.clone();
69
let instance_pre = instance_pre.clone();
70
std::thread::spawn(move || -> Result<()> {
71
for _ in 0..999 {
72
// Create a new store for this instance.
73
let mut store = Store::new(&engine, ());
74
// Instantiate our module in this store.
75
let instance = instance_pre.instantiate(&mut store)?;
76
// Call the instance's `run` function!
77
let _result = instance
78
.get_typed_func::<(), i32>(&mut store, "run")?
79
.call(&mut store, ());
80
}
81
Ok(())
82
})
83
})
84
.collect();
85
86
// Wait for the threads to finish.
87
for h in handles.into_iter() {
88
h.join().map_err(|_| anyhow!("thread panicked!"))??;
89
}
90
91
Ok(())
92
}
93
94