#wasm-module #initialization #instantiation

bin+lib wizer

WebAssembly 预初始化器

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

Download history 1175/week @ 2024-04-30 689/week @ 2024-05-07 503/week @ 2024-05-14 393/week @ 2024-05-21 822/week @ 2024-05-28 407/week @ 2024-06-04 774/week @ 2024-06-11 956/week @ 2024-06-18 810/week @ 2024-06-25 841/week @ 2024-07-02 469/week @ 2024-07-09 388/week @ 2024-07-16 508/week @ 2024-07-23 687/week @ 2024-07-30 296/week @ 2024-08-06 428/week @ 2024-08-13

1,994 个月下载量
用于 weval

Apache-2.0 WITH LLVM-exception

15MB
293K SLoC

TypeScript 243K SLoC // 0.3% comments JavaScript 48K SLoC // 0.1% comments Rust 1.5K SLoC // 0.1% comments Shell 34 SLoC // 0.3% comments

Wizer

WebAssembly 预初始化器!

一个 Bytecode Alliance 项目

build status zulip chat Documentation Status

API 文档 | 贡献 | 聊天

关于

不要等待您的 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