#互联网计算机 #canister #dfinity

bin+lib ic-wasm

一个针对在互联网计算机上运行的canister进行Wasm转换的库

25次发布

0.8.1 2024年8月20日
0.8.0 2024年7月9日
0.7.2 2024年4月6日
0.7.1 2024年3月20日
0.1.3 2022年7月7日

#506 in 神奇豆子

Download history 4343/week @ 2024-05-04 5174/week @ 2024-05-11 5041/week @ 2024-05-18 7329/week @ 2024-05-25 7193/week @ 2024-06-01 5998/week @ 2024-06-08 6027/week @ 2024-06-15 5261/week @ 2024-06-22 4769/week @ 2024-06-29 5677/week @ 2024-07-06 5137/week @ 2024-07-13 5088/week @ 2024-07-20 4175/week @ 2024-07-27 5577/week @ 2024-08-03 4309/week @ 2024-08-10 5469/week @ 2024-08-17

每月20,685次下载

Apache-2.0

95KB
2K SLoC

ic-wasm

一个针对在互联网计算机上运行的Wasm canister进行转换的库

可执行文件

要安装ic-wasm可执行文件,请运行

$ cargo install ic-wasm

元数据

管理Wasm模块的元数据。

用法:ic-wasm <input.wasm> [-o <output.wasm>] metadata [name] [-d <text content> | -f <file content>] [-v <public|private>]

  • 列出当前元数据部分
$ ic-wasm input.wasm metadata
  • 列出特定元数据内容
$ ic-wasm input.wasm metadata candid:service
  • 添加/覆盖私有元数据部分

注意:私有元数据部分的哈希值任何人都可以读取。如果部分包含低熵数据,攻击者可能可以暴力破解内容。

$ ic-wasm input.wasm -o output.wasm metadata new_section -d "hello, world"
  • 从文件添加/覆盖公共元数据部分
$ ic-wasm input.wasm -o output.wasm metadata candid:service -f service.did -v public

信息

打印关于Wasm canister的信息

用法:ic-wasm <input.wasm> info

收缩

移除未使用的函数和调试信息。

注意:在收缩过程中,icp元数据部分被保留。

用法: ic-wasm <input.wasm> -o <output.wasm> shrink

优化

wasm-opt调用wasm优化。

优化器提供了不同的优化级别可供选择。

性能级别(针对运行时优化)

  • O4
  • O3(默认设置:最佳循环使用率最小化)
  • O2
  • O1
  • O0(无优化)

代码大小级别(针对二进制大小优化)

  • Oz(最佳代码大小最小化)
  • Os

推荐的设置(O3)将Motoko程序的计算周期使用率减少约10%,Rust程序减少约4%。两种语言的代码大小都减少了约16%。

注意:在优化过程中,icp元数据部分被保留。

用法: ic-wasm <input.wasm> -o <output.wasm> optimize <level>

wasm-opt公开了两个额外的标志

  • --inline-functions-with-loops
  • --always-inline-max-function-size<FUNCTION_SIZE>

这些被用于大胆地内联函数,这在Motoko程序中很常见。由于新的成本模型,内联带有循环的函数可以带来很大的性能提升,但也会导致二进制大小大幅增加。由于二进制大小增加,我们可能无法在Wasm模块内的actor类中应用这种内联。

例如: ic-wasm <input.wasm> -o <output.wasm> optimize O3 --inline-functions-with-loops --always-inline-max-function-size 100

资源

限制资源使用,主要用于Motoko Playground

用法: ic-wasm <input.wasm> -o <output.wasm> resource --remove_cycles_transfer --limit_stable_memory_page 1024

仪器(实验性)

仪器可以记录canister方法以将执行跟踪输出到稳定内存。

用法: ic-wasm <input.wasm> -o <output.wasm> instrument --trace-only func1 --trace-only func2 --start-page 16 --page-limit 30

测量过的罐体具有以下附加端点

  • __get_cycles: () -> (int64) query. 获取当前周期计数器。
  • __get_profiling: (idx:int32) -> (vec { record { int32; int64 }}, opt int32) query. 获取执行跟踪日志,从 idx 0 开始。如果日志大于 2M,则返回前 2M 的跟踪内容,以及下一个 idx 以获取下一个 2M 数据块。
  • __toggle_tracing: () -> (). 禁用/启用执行跟踪的记录。
  • __toggle_entry: () -> (). 禁用/启用为每个更新调用清除执行跟踪。
  • icp:public name 元数据。用于将执行跟踪中的 func_id 映射到函数名。

当提供 --trace-only 标志时,计数器和跟踪日志仅在执行该函数期间发生,而不是跟踪整个更新调用。请注意,该函数本身必须是不可递归的。

与升级和稳定内存一起工作

默认情况下,执行跟踪存储在稳定内存的前几页(最多 32 页)中。如果没有用户端支持,我们无法对升级或访问稳定内存的代码进行性能分析。如果罐体可以在 canister_init 中预先分配稳定内存的固定区域,我们可以通过 --start-page 标志将此地址传递给 ic-wasm,这样跟踪就会被写入此预先分配的空间,而不会破坏稳定内存的其他访问。

另一个可选标志 --page-limit 指定稳定内存中预先分配的页面数。默认情况下,它设置为 4096 页(256MB)。我们只存储最多 page-limit 页的跟踪,剩余的跟踪将被丢弃。

推荐通过 Motoko 中的 Region 库和 Rust 中的 ic-stable-structures 预先分配稳定内存。但开发者可以自由使用任何其他库,甚至原始的稳定内存系统 API 来预先分配空间,只要开发者可以保证预分配的空间不会被其他代码访问。

以下是在 Motoko 中预先分配稳定内存的代码示例(带有 --start-page 16

import Region "mo:base/Region";
actor {
  stable let profiling = do {
    let r = Region.new();
    ignore Region.grow(r, 4096);  // Increase the page number if you need larger log space
    r;
  };
  ...
}

以及在 Rust 中(带有 --start-page 1

use ic_stable_structures::{
    memory_manager::{MemoryId, MemoryManager},
    writer::Writer,
    DefaultMemoryImpl, Memory,
};
thread_local! {
    static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> =
        RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));
}
const PROFILING: MemoryId = MemoryId::new(0);
const UPGRADES: MemoryId = MemoryId::new(1);

#[ic_cdk::init]
fn init() {
    let memory = MEMORY_MANAGER.with(|m| m.borrow().get(PROFILING));
    memory.grow(4096);  // Increase the page number if you need larger log space
    ...
}
#[ic_cdk::pre_upgrade]
fn pre_upgrade() {
    let mut memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES));
    ...
}
#[ic_cdk::post_upgrade]
fn post_upgrade() {
    let memory = MEMORY_MANAGER.with(|m| m.borrow().get(UPGRADES));
    ...
}

当前限制

  • 如果没有从用户代码中预先分配稳定内存,我们无法对升级或访问稳定内存的代码进行性能分析。如果您预先分配了大量的稳定内存页并指定了 page-limit 标志,则可以分析大于 256M 的跟踪。更大的跟踪可以通过 __get_profiling 以流式传输方式检索。
  • 由于预分配发生在 canister_init 中,我们无法对 canister_init 进行性能分析。
  • 如果存在心跳,则很难测量任何其他方法调用。也很难测量特定的心跳事件。
  • 无法测量查询调用。
  • 没有并发调用。

要将 ic-wasm 作为库使用,请将以下内容添加到您的 Cargo.toml

[dependencies.ic-wasm]
default-features = false

贡献

查看我们的CONTRIBUTING 以开始。

依赖项

~15–26MB
~419K SLoC