19 个稳定版本 (6 个主要版本)
新 7.0.0 | 2024 年 8 月 20 日 |
---|---|
6.0.0 | 2024 年 4 月 15 日 |
5.0.0 | 2024 年 3 月 13 日 |
4.0.0 | 2024 年 1 月 3 日 |
1.3.0 | 2021 年 3 月 26 日 |
#1101 in WebAssembly
1,994 个月下载量
用于 weval
15MB
293K SLoC
关于
不要等待您的 Wasm 模块自行初始化,预先初始化它!Wizer 会实例化您的 WebAssembly 模块,执行其初始化函数,然后将初始化后的状态快照到新的 WebAssembly 模块中。现在,您可以使用这个新的、预先初始化的 WebAssembly 模块立即开始运行,而无需让用户等待第一次设置代码完成。
您可预期的启动延迟改进将取决于您的 WebAssembly 模块在准备就绪之前需要执行多少初始化工作。一些初始基准测试显示,使用 Wizer,实例化和初始化速度可以提高 1.35 到 6.00 倍,具体取决于工作负载。
程序 | 没有 Wizer | 使用 Wizer | 加速 |
---|---|---|---|
正则表达式 |
248.85 us | 183.99 us | 1.35 倍更快 |
UAP | 98.297 ms | 16.385 ms | 6.00 倍更快 |
并非每个程序都会看到实例化和启动延迟的改进。例如,Wizer 通常会增加 Wasm 模块的 Data
部分的大小,这可能会对 Web 上的网络传输时间产生负面影响。然而,要了解您的 Wasm 模块是否会看到改进,最好的方法是亲自尝试!添加一个初始化函数并不困难。
最后,您可以通过在预初始化模块上运行 wasm-opt
来进一步改进性能。除了 wasm-opt
常带来的好处之外,该模块可能有一大堆不再需要的仅用于初始化的代码,而 wasm-opt
可以将其删除。
安装
从 发布页面 下载预构建版本。解压缩二进制文件并将其放置在您的 $PATH 中。
或者您可以通过 cargo
进行安装。
cargo install wizer --all-features
示例用法
首先,请确保您的 Wasm 模块导出一个名为 wizer.initialize
的初始化函数。例如,在 Rust 中您可以这样导出:
#[export_name = "wizer.initialize"]
pub extern "C" fn init() {
// Your initialization code goes here...
}
关于一个完整的 C++ 示例,请参见 这里。
然后,如果您的 Wasm 模块名为 input.wasm
,运行 wizer
CLI。
wizer input.wasm -o initialized.wasm
现在您已经在 initialized.wasm
处获得了一个预初始化的 Wasm 模块版本!
更多详细信息、标志和选项可以通过 --help
查看。
wizer --help
注意事项
-
初始化函数可能不会调用任何导入的函数。这样做将触发陷阱,并且
wizer
将退出。然而,您可以通过--allow-wasi
标志允许 WASI 调用。 -
Wasm 模块可能无法导入全局变量、表或内存。
-
尚不支持引用类型。关于如何快照
externref
表的最佳方法目前尚不明确。
将 Wizer 作为库使用
在您的 Cargo.toml
中添加一个依赖项。
# Cargo.toml
[dependencies]
wizer = "1"
然后使用 wizer::Wizer
构造函数来配置和运行 Wizer。
use wizer::Wizer;
let input_wasm = get_input_wasm_bytes();
let initialized_wasm_bytes = Wizer::new()
.allow_wasi(true)?
.run(&input_wasm)?;
使用自定义链接器与 Wizer
如果您希望模块能够在实例化时导入其他模块,您可以使用 make_linker(...)
构造函数方法来提供自己的链接器,例如:
use wizer::Wizer;
let input_wasm = get_input_wasm_bytes();
let initialized_wasm_bytes = Wizer::new()
.make_linker(Some(Rc::new(|e: &wasmtime::Engine| {
let mut linker = wasmtime::Linker::new(e);
linker.func_wrap("foo", "bar", |x: i32| x + 1)?;
Ok(linker)
})))
.run(&input_wasm)?;
请注意,目前 allow_wasi(true)
和自定义链接器是互斥的。
它是如何工作的?
首先,我们使用 Wasmtime 实例化输入 Wasm 模块并运行初始化函数。然后我们记录 Wasm 实例的状态。
- 它的全局变量的值是什么?
- 内存的哪些区域是非零的?
然后我们通过直接将全局变量初始化为其记录的状态来重写 Wasm 二进制文件,并删除模块的旧数据段,并用我们记录的每个非零内存区域的数据段替换它们。
想了解更多细节?请查看 2021 年 WebAssembly Summit 的演讲 "Hit the Ground Running: Wasm Snapshots for Fast Start Up"。
依赖项
~32–44MB
~845K SLoC