RustのWasm周りのクレートまとめと、Trunkを使ってRustで書いたWasmをブラウザ上で簡単に実行する
はじめに
この記事ではRustのWasmを使う際に便利なライブラリたちをまとめて、その後Trunkというツールを利用してRustでWasmを書いて実行するところまでを試してみます。
記事執筆時のRustのバージョンは1.61.0です。
RustでのWasmの実行周りのエコシステムまとめ
RustはWasmをコンパイルのターゲットとして公式でサポートしています。
wasm32-unknown-unknown
というターゲットをrustupで追加することでWasm向けにRustをコンパイルできます。
ただしこれ単体で使うより、さらに周辺ライブラリを組み合わせて使うことが多いようです。
Rustでは周辺のライブラリなどを使うことでより便利にWasmを利用できます。
以下にRustでWasmを使う場合にお世話になるであろう周辺ライブラリなどを紹介します。
また、今回紹介しきれない範囲などについて、wasm-bindgenのガイドにとても詳しくRustでWasmを触るための何もかもが書かれているのでそちらも適宜読むと良いでしょう。
wasm-bindgen
wasm-bindgenはWasmとJavaScriptの間の糊付けを担当します。
例えば次のように#[wasm_bindgen]
をつけて関数を宣言することで、Rustで書いたWasmの中からJavaScriptの関数を利用したり、逆にRustで書いたWasmの関数をJavaScriptから呼べるようになります。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
import { greet } from "./hello_world";
greet("World!");
現在、Wasmは実行する際にはJavaScriptの内部から呼び出す必要があり、JavaScriptとの糊付けのコードはだいたい必須となるため、wasm-bindgenは多くの場合必須となるでしょう。
wasm-bindgenはJsValueというJavaScriptのオブジェクトをRustで表現した型を持っています。
このJsValueをブラウザAPIの型として扱う場合、例えばNumber型であったりArray型のようなJavaScript固有の型、あるいはHtmlInputElementなどのようなブラウザのオブジェクト固有の型については、後述のjs_sys及びweb_sysクレートを使います。
wasm-bindgenのserde-serializeというfeatureを有効にすることで、JsValueとJSONへシリアライズ/デシリアライズできる値との変換ができるようになります。
これによってJavaScriptから渡されるObjectをserdeでRustに取り込むことなどが可能になります。
場合によってはこの機能は後述のserde-wasm-bindgenを利用したほうが効率が良いかもしれません。
wasm-bindgen-cli
wasm-bindgen-cli0は、前述のwasm-bindgenをつけてビルドしたRustの生成するWasmを食わせて新たに使いやすいWasmやJavaScriptコードなどを生成するツールです。
wasm-bindgen-cliを利用すると、Wasmファイルの他に糊付けのためのJavaScriptコードも吐き出してくれるので、JavaScriptからまるでWasmの関数を直接呼び出したりするように使うことができます。
糊付けのコードの種類に応じて次のtargetを--target [target name]
として指定できます。
- bundler: Webpackなどでバンドルするためのライブラリとしての糊付けコード
- web: ブラウザから読み込まれるモジュールとして使う糊付けコード
- nodejs: Node.jsのrequireで読み込める形式としての糊付けコード
- deno: Denoからインポートできるモジュール用の糊付けコード
- no-modules: ブラウザから読み込まれるモジュールだが、Webと違いES Moduleに対応していない環境に向けた糊付けのコード
targetについては詳しくはドキュメントのページを読むと良いでしょう。
例えば上記のmain.rs
を--target web
で呼び出す場合、次のようなwasm_bindgen_test.js
とwasm_bindgen_test_bg.wasm
というバイナリが生成されています。
(ついでにwasm_bindgen_test_bg.wasm.d.ts
とwasm_bindgen_test.d.ts
というTypeScriptの型定義ファイルも生成されますが、これはオプションで無効化もできます)
wasm_bindgen_test.js
let wasm;
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let WASM_VECTOR_LEN = 0;
const cachedTextEncoder = new TextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
/**
* @param {string} name
*/
export function greet(name) {
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
wasm.greet(ptr0, len0);
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else {
throw e;
}
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
}
async function init(input) {
if (typeof input === 'undefined') {
input = new URL('wasm_bindgen_test_bg.wasm', import.meta.url);
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbg_alert_0bebe9e6d7aece39 = function(arg0, arg1) {
alert(getStringFromWasm0(arg0, arg1));
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
return wasm;
}
export default init;
#[wasm_bindgen]
をつけて宣言したgreet
関数が用意されているのがわかります。
WasmとJavaScriptのデータのやり取りにはUint8Array
などの特定の型を使う必要があるため、文字列をエンコード及びデコードする仕組みも合わせて書き出されています。
また、Wasmの処理時にWasmのサイズの最適化も行ってくれます。
Rustがデフォルトで吐き出すWasmにはリリースビルドでもデバッグ用情報などが含まれており、かなりサイズが大きいものとなります。
例えば先のmain.rs
はcargo build --release
した場合、私の手元の環境では1655KBのWasmが吐き出されました。
これをwasm-bindgen-cliに食べさせた結果吐き出されるWasmは26KBでした。
大きくファイルサイズが減っていることがわかります。
Trunkを使う場合、wasm-bindgenの適用は勝手にやってくれるので、直接wasm-bindgen-cliを叩く必要はないかもしれません。
js_sys
js_sysはJavaScriptの型をRustで扱うためのクレートです。
JavaScriptのNumber型やJsString型などを提供します。
web_sys
web_sysはブラウザのAPIやブラウザ固有の型をRustで表現したものとなります。
HtmlInputElementやHtmlDivElementなどのブラウザ固有の型を扱う際に必要になります。
特にEventTargetを特定の型として取得する場合など、ダイナミックなキャストが必要になる場面も多く、その場合dyn_cast
などを使います。
dyn_cast
はResult
型を返すので、dyn_cast
とunwrap
が入り乱れるなかなか治安の悪いコードを書くことになります。
js_sysやweb_sysでまるでWasmの中から直接JavaScriptの値やDOMを触っているような書き味でプログラムをかけますが、裏側ではJavaScriptのグルーコードを大量に生成してwasmにバインドしたそれらの関数の呼び出しなどに振り替えているようなので、WasmとJavaScriptの世界のやり取りが必要なためそこまで効率は良くないかもしれません。
「WebAssembly Reference Types」を利用すると生成されるJavaScriptのグルーコードが減り、効率も多少良くなることが期待されます。
「WebAssembly Reference Types」については次の記事がよくまとまっていて参考になります。
2022年6月11日の現状ではTrunkを使うとこのreference typesはうまく動きません。
Trunkにはdata-reference-typesという属性が指定できるようになっていますが、これによる指定ではwasm-bindgenのオプションのみ切り替わり、wasm-optのオプションが渡されないためリリースビルドでエラーが出てしまいます。
この問題についてはこちらのPRで直りそうに見えますが、現状まだ取り込まれていないようです。
wasm-bindgen-futures
Wasm環境下ではAtomicなオブジェクトを標準で使うのはまだ整備されていないため、ArcやMutexなどの仕様が制限されます。
それによってtokioなどの非同期ランタイムがWasm上ではうまく動きません。
wasm-bindgen-futuresはWasm環境下でも動く非同期ランタイムを提供します。
この非同期ランタイムはJavaScriptのPromiseの実行と結びついており、JavaScriptのPromiseとRustのFutureを相互に変換するような仕組みも用意してくれます。
gloo
WasmからDOMを操作したり、ブラウザのAPIを利用したりする際には、決まりきったコードを何度も書く必要が出てきます。
そのような処理を切り出して、ブラウザAPIをRustから叩く際の辛さを軽減してくれるライブラリです。
serde-wasm-bindgen
前述したserde-serializeというfeatureはJsValueとRustの値のやり取りにJSONのシリアライズとデシリアライズの機構を使っていました。
これは数値型などの直接扱えるものでもJSONを経由しているということで若干のムダがあります。
こちらのserde-wasm-bindgenはJSONを経由せずに直接やり取りできるものはやり取りするため、コードサイズが小さくなったりMapやSetをやり取りできるあたりが優れているとのことです。
wasm-pack
wasm-packはwasm-bindgenをラップしたより扱いやすいCLIツールです。
次のようにしてインストールが可能です。
$ cargo install wasm-pack
wasm-packを使うことで、ビルドしてwasm-bindgen-cliでさらに変換処理を行い、npmで配布可能なパッケージにするという多段階必要なビルド手順をまとめることが可能です。
またnew
コマンドのようなテンプレートから生成する機能などもあり、より手軽にWasmの実行を行えます。
後述のTrunkとの違いは、wasm-packはwebpackなどのJavaScript側で使われるバンドラーなどと合わせて使うことが想定されていることです。
webpackと合わせて使わない場合には今回のテーマであり後述するTrunkを利用したほうがより簡単にWasmの実行を行えます。
wasm-opt
binaryenというリポジトリでwasm-optというツール含むいくつかのツールが作られています。
wasm-optはその名の通りWasmの最適化をしてくれるツールです。
与えるオプションによって実行速度の最適化ではなくファイルサイズの最適化ができます。
後述のTrunkに組み込まれていて、直接使うことなく最適化を行えます。
前述のmain.rsをwasm-bindgenに通したあとの26KBのWasmを、さらにwasm-optに最適化オプション-Oz
のファイルサイズを小さくするような設定でかけてみると、17KBとなりました。
twiggy
twiggyはWasmバイナリファイルの内訳を表示することなどができます。
ファイルサイズの確認などに使えます。
上記main.rsをリリースビルドしたWasmをtwiggy top
にかけてみた結果は次のとおりです。
twiggy top main.wasm
$ twiggy top .\target\wasm32-unknown-unknown\release\wasm_bindgen_test.wasm
Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
599355 ┊ 35.39% ┊ custom section '.debug_str'
384623 ┊ 22.71% ┊ custom section '.debug_info'
295700 ┊ 17.46% ┊ custom section '.debug_line'
214568 ┊ 12.67% ┊ custom section '.debug_pubnames'
162280 ┊ 9.58% ┊ custom section '.debug_ranges'
8777 ┊ 0.52% ┊ "function names" subsection
4917 ┊ 0.29% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::malloc::hcec496a2198179fe
3932 ┊ 0.23% ┊ custom section '.debug_abbrev'
1429 ┊ 0.08% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::free::h5fba2897807212aa
1119 ┊ 0.07% ┊ __rdl_realloc
1062 ┊ 0.06% ┊ core::str::count::do_count_chars::h8068e62995a060d4
1031 ┊ 0.06% ┊ core::fmt::Formatter::pad_integral::ha4f8dd1eb5755fda
987 ┊ 0.06% ┊ core::fmt::Formatter::pad::hc84bfca380790d9b
770 ┊ 0.05% ┊ data[0]
727 ┊ 0.04% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::dispose_chunk::h15f89ab1d45de9ae
704 ┊ 0.04% ┊ core::fmt::write::h3e26ed3eda73f0a3
558 ┊ 0.03% ┊ alloc::fmt::format::h588637f2f2183a4d
501 ┊ 0.03% ┊ dlmalloc::Dlmalloc<A>::malloc::hecadd78677587853
494 ┊ 0.03% ┊ __externref_table_alloc
393 ┊ 0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::release_unused_segments::h4826643b506d455c
378 ┊ 0.02% ┊ <alloc::string::String as core::fmt::Write>::write_char::hfcad3e975f1a678c
376 ┊ 0.02% ┊ alloc::string::String::push::he882a8f290dcb8c3
364 ┊ 0.02% ┊ core::fmt::num::imp::fmt_u64::h0c2fe44c27dae252
352 ┊ 0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::insert_large_chunk::h0ab04c16e556807e
346 ┊ 0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::unlink_large_chunk::h3cd39bebabb3864d
324 ┊ 0.02% ┊ compiler_builtins::mem::memcpy::h78a567d3a58ab6e5
324 ┊ 0.02% ┊ custom section '.debug_pubtypes'
321 ┊ 0.02% ┊ __externref_heap_live_count
317 ┊ 0.02% ┊ __externref_table_dealloc
308 ┊ 0.02% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::take_box::h5fff44acdfbac4e7
302 ┊ 0.02% ┊ std::panicking::rust_panic_with_hook::he2a025723e105e28
263 ┊ 0.02% ┊ custom section '__wasm_bindgen_unstable'
222 ┊ 0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h2d7a97b6f3432e07
222 ┊ 0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h20a6726722873456
222 ┊ 0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h1397f88c4b936258
222 ┊ 0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h00dea0a6d40548b6
203 ┊ 0.01% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::get::h79854d279d39b63d
194 ┊ 0.01% ┊ std::panicking::begin_panic_handler::{{closure}}::hd9f8c213ec91b9d5
189 ┊ 0.01% ┊ greet
184 ┊ 0.01% ┊ alloc::raw_vec::finish_grow::h98b255e8c87ba6ac
184 ┊ 0.01% ┊ alloc::raw_vec::finish_grow::h7642e1a95a96c333
157 ┊ 0.01% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::init_top::h18355a6f078d958f
150 ┊ 0.01% ┊ core::result::unwrap_failed::h68fdaca771c68bb6
134 ┊ 0.01% ┊ std::alloc::default_alloc_error_hook::h0876b7eb4919815d
118 ┊ 0.01% ┊ <&mut W as core::fmt::Write>::write_fmt::he72a95b1e7bc46cb
118 ┊ 0.01% ┊ <&mut W as core::fmt::Write>::write_fmt::hcb1df0cddb10ef35
94 ┊ 0.01% ┊ core::fmt::Formatter::pad_integral::write_prefix::h9ddec898718cb90a
91 ┊ 0.01% ┊ rust_begin_unwind
90 ┊ 0.01% ┊ <&mut W as core::fmt::Write>::write_str::h3169351e95b802c7
90 ┊ 0.01% ┊ <&mut W as core::fmt::Write>::write_str::hd4b6ba77fb1193cc
86 ┊ 0.01% ┊ core::panicking::panic::hc28e7cc2aa792341
80 ┊ 0.00% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::take_box::h8e753108593700f0
80 ┊ 0.00% ┊ alloc::raw_vec::capacity_overflow::h1de937e4490b6dee
78 ┊ 0.00% ┊ core::panicking::panic_fmt::hb02133958c1e7d35
67 ┊ 0.00% ┊ import __wbindgen_externref_xform__::__wbindgen_externref_table_set_null
67 ┊ 0.00% ┊ custom section 'producers'
63 ┊ 0.00% ┊ import __wbindgen_externref_xform__::__wbindgen_externref_table_grow
60 ┊ 0.00% ┊ __wbindgen_describe___wbg_alert_0bebe9e6d7aece39
59 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::alloc::h8b3509d622dedd6b
56 ┊ 0.00% ┊ import __wbindgen_placeholder__::__wbg_alert_0bebe9e6d7aece39
55 ┊ 0.00% ┊ __wbindgen_malloc
51 ┊ 0.00% ┊ export "__wbindgen_describe___wbg_alert_0bebe9e6d7aece39"
51 ┊ 0.00% ┊ rust_panic
49 ┊ 0.00% ┊ __externref_drop_slice
47 ┊ 0.00% ┊ import __wbindgen_placeholder__::__wbindgen_describe
44 ┊ 0.00% ┊ __wbindgen_realloc
44 ┊ 0.00% ┊ core::ptr::drop_in_place<std::error::<impl core::convert::From<alloc::string::String> for alloc::boxed::Box<dyn std::error::Error+core::marker::Sync+core::marker::Send>>::from::StringError>::h9ce0522b145fe6fa
44 ┊ 0.00% ┊ core::ptr::drop_in_place<std::panicking::begin_panic_handler::PanicPayload>::h636ad6d68e279e0d
41 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::set_inuse::hd80515990c160bc8
40 ┊ 0.00% ┊ dlmalloc::dlmalloc::Segment::holds::h1a60be87238e9919
39 ┊ 0.00% ┊ rust_oom
37 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::set_free_with_pinuse::h64fe80d61b111714
36 ┊ 0.00% ┊ custom section 'name' headers
35 ┊ 0.00% ┊ <core::fmt::Error as core::fmt::Debug>::fmt::hb67b0fb623137665
34 ┊ 0.00% ┊ core::option::Option<T>::unwrap::haa480509e27ff8fc
32 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse::hb9f654c37e5fb327
31 ┊ 0.00% ┊ elem[0]
30 ┊ 0.00% ┊ export "__externref_heap_live_count"
30 ┊ 0.00% ┊ core::option::Option<T>::unwrap::h3bbfb90b442ebef6
30 ┊ 0.00% ┊ dlmalloc::dlmalloc::TreeChunk::leftmost_child::h8bd9454cc3d402c7
28 ┊ 0.00% ┊ export "__wbindgen_describe_greet"
28 ┊ 0.00% ┊ export "__externref_table_dealloc"
27 ┊ 0.00% ┊ custom section '__wasm_bindgen_unstable' headers
26 ┊ 0.00% ┊ export "__externref_table_alloc"
26 ┊ 0.00% ┊ __wbindgen_exn_store
26 ┊ 0.00% ┊ std::sys_common::backtrace::__rust_end_short_backtrace::h6efd730283875809
26 ┊ 0.00% ┊ <&T as core::fmt::Debug>::fmt::hea96acd558b28457
25 ┊ 0.00% ┊ export "__externref_drop_slice"
25 ┊ 0.00% ┊ __rust_realloc
24 ┊ 0.00% ┊ __wbindgen_free
24 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk::h11a8a5342df751be
23 ┊ 0.00% ┊ export "__wbindgen_exn_store"
22 ┊ 0.00% ┊ <&T as core::fmt::Display>::fmt::hcaadeff9a1654879
22 ┊ 0.00% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::get::h486eccde219d443e
22 ┊ 0.00% ┊ <&T as core::fmt::Display>::fmt::h8228500dd0a93de5
21 ┊ 0.00% ┊ export "__wbindgen_realloc"
21 ┊ 0.00% ┊ __rust_alloc
20 ┊ 0.00% ┊ export "__wbindgen_malloc"
20 ┊ 0.00% ┊ <&mut W as core::fmt::Write>::write_char::h735ba2e2255ac07c
20 ┊ 0.00% ┊ dlmalloc::dlmalloc::leftshift_for_tree_index::h6fffd47072ccebc0
20 ┊ 0.00% ┊ custom section '.debug_pubnames' headers
19 ┊ 0.00% ┊ <&mut W as core::fmt::Write>::write_char::h7f2928ac137cbae7
19 ┊ 0.00% ┊ core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt::h6bf974e8791b3fa6
19 ┊ 0.00% ┊ custom section '.debug_pubtypes' headers
18 ┊ 0.00% ┊ export "__wbindgen_free"
18 ┊ 0.00% ┊ dlmalloc::dlmalloc::align_up::hf1f4ea6608931a25
18 ┊ 0.00% ┊ custom section '.debug_ranges' headers
17 ┊ 0.00% ┊ __rust_dealloc
17 ┊ 0.00% ┊ dlmalloc::dlmalloc::left_bits::h4c3ee1c04a9d948c
17 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::clear_pinuse::h28b4b6bfa0365301
17 ┊ 0.00% ┊ custom section '.debug_abbrev' headers
16 ┊ 0.00% ┊ <str as core::fmt::Display>::fmt::he02814d332326528
16 ┊ 0.00% ┊ memcpy
16 ┊ 0.00% ┊ custom section '.debug_info' headers
16 ┊ 0.00% ┊ custom section '.debug_line' headers
15 ┊ 0.00% ┊ __rust_alloc_error_handler
15 ┊ 0.00% ┊ <T as core::any::Any>::type_id::hf1eb4553966c7029
15 ┊ 0.00% ┊ <T as core::any::Any>::type_id::hf86124a39f31439b
15 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::cinuse::hfcc18d9ee069b807
15 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::inuse::h86972c896758fa35
15 ┊ 0.00% ┊ dlmalloc::dlmalloc::Segment::top::had8e50e872afff9d
15 ┊ 0.00% ┊ core::intrinsics::const_eval_select::hbff2fd2057209df4
15 ┊ 0.00% ┊ core::ops::function::FnOnce::call_once::h7538d6968a96c4c6
15 ┊ 0.00% ┊ alloc::alloc::handle_alloc_error::rt_error::h215dddd0f4495f99
15 ┊ 0.00% ┊ alloc::alloc::handle_alloc_error::h0693183370a7902c
15 ┊ 0.00% ┊ __rg_oom
15 ┊ 0.00% ┊ core::ops::function::FnOnce::call_once::h5753b14cff916f0e
15 ┊ 0.00% ┊ <T as core::any::Any>::type_id::hc91c1766c0a8e26b
15 ┊ 0.00% ┊ custom section '.debug_str' headers
14 ┊ 0.00% ┊ export "__heap_base"
14 ┊ 0.00% ┊ __rdl_alloc
14 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk::h81fc9155883489ea
13 ┊ 0.00% ┊ export "__data_end"
13 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::mmapped::h04354a447c7ef83b
12 ┊ 0.00% ┊ <() as wasm_bindgen::describe::WasmDescribe>::describe::h8066b3287422c15b
12 ┊ 0.00% ┊ <str as wasm_bindgen::describe::WasmDescribe>::describe::h09e5dc149b174418
12 ┊ 0.00% ┊ __rdl_dealloc
12 ┊ 0.00% ┊ dlmalloc::dlmalloc::least_bit::h5164fc99df6558f5
12 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::size::ha342d078107e0f53
12 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::pinuse::h3e366cef7e528bba
12 ┊ 0.00% ┊ dlmalloc::dlmalloc::Segment::is_extern::h6fdd496f2978bb35
12 ┊ 0.00% ┊ dlmalloc::dlmalloc::Segment::sys_flags::h4d6b01219f9e07b9
12 ┊ 0.00% ┊ custom section 'producers' headers
11 ┊ 0.00% ┊ wasm_bindgen::externref::internal_error::h1e4496ca9551d147
11 ┊ 0.00% ┊ wasm_bindgen::__rt::malloc_failure::h8137027072480bce
11 ┊ 0.00% ┊ code section headers
10 ┊ 0.00% ┊ type[13]: (i32, i32, i32, i32, i32, i32) -> i32
10 ┊ 0.00% ┊ wasm_bindgen::__rt::link_mem_intrinsics::h84678cad5a3f00f2
9 ┊ 0.00% ┊ type[12]: (i32, i32, i32, i32, i32) -> i32
9 ┊ 0.00% ┊ export "memory"
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::plus_offset::hf594a71617f2958c
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::minus_offset::ha660e14327ac3e4c
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::to_mem::h4b386d4e48d965cf
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::from_mem::h75b6b5095597031a
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::TreeChunk::next::h6a3f651c010e6975
9 ┊ 0.00% ┊ dlmalloc::dlmalloc::TreeChunk::prev::h052e4d2e0cbc3ff0
9 ┊ 0.00% ┊ core::panic::panic_info::PanicInfo::message::h102fddb6becb8eab
9 ┊ 0.00% ┊ core::panic::panic_info::PanicInfo::location::h5dfcade149d8a598
9 ┊ 0.00% ┊ core::panic::panic_info::PanicInfo::can_unwind::hf0853bc09675a7a1
8 ┊ 0.00% ┊ type[7]: (i32, i32, i32, i32) -> i32
8 ┊ 0.00% ┊ type[11]: (i32, i32, i32, i32, i32) -> nil
8 ┊ 0.00% ┊ global[0]
8 ┊ 0.00% ┊ global[1]
8 ┊ 0.00% ┊ global[2]
8 ┊ 0.00% ┊ export "greet"
8 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::page_size::h88a1bbbf4b8674f2
8 ┊ 0.00% ┊ wasm magic bytes
7 ┊ 0.00% ┊ type[1]: (i32, i32, i32) -> i32
7 ┊ 0.00% ┊ type[10]: (i32, i32, i32, i32) -> nil
7 ┊ 0.00% ┊ type[14]: (i64, i32, i32) -> i32
6 ┊ 0.00% ┊ type[2]: (i32, i32) -> i32
6 ┊ 0.00% ┊ type[6]: (i32, i32, i32) -> nil
6 ┊ 0.00% ┊ std::process::abort::hbba08b3d6df850f8
6 ┊ 0.00% ┊ __rust_start_panic
6 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::fencepost_head::h343fc8d31cab4021
6 ┊ 0.00% ┊ dlmalloc::dlmalloc::Chunk::mem_offset::hb26f0a8f126c0579
6 ┊ 0.00% ┊ dlmalloc::dlmalloc::TreeChunk::chunk::h9cbb25ca6296593a
6 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::remap::h0979387267a4a643
6 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free_part::hef5dee6eb24bcc8c
6 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free::h0aa881b9e76b9b02
6 ┊ 0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::can_release_part::hc2a2319ea9025de0
5 ┊ 0.00% ┊ type[0]: (i32, i32) -> nil
5 ┊ 0.00% ┊ type[4]: (i32) -> i32
5 ┊ 0.00% ┊ type[9]: (i32) -> i64
4 ┊ 0.00% ┊ type[3]: (i32) -> nil
4 ┊ 0.00% ┊ type[8]: () -> i32
4 ┊ 0.00% ┊ import section headers
4 ┊ 0.00% ┊ table[0]
4 ┊ 0.00% ┊ export section headers
4 ┊ 0.00% ┊ wasm_bindgen::externref::link_intrinsics::h8e3c0da2384b97d7
4 ┊ 0.00% ┊ core::ptr::drop_in_place<&mut std::io::Write::write_fmt::Adapter<alloc::vec::Vec<u8>>>::ha5213606bfbb1ca2
4 ┊ 0.00% ┊ core::ptr::drop_in_place<&u8>::h52ad2d112c7e2ce3
4 ┊ 0.00% ┊ core::ptr::drop_in_place<&core::iter::adapters::copied::Copied<core::slice::iter::Iter<u8>>>::h0e2bcd53588f6395
4 ┊ 0.00% ┊ data section headers
3 ┊ 0.00% ┊ type[5]: () -> nil
3 ┊ 0.00% ┊ type section headers
3 ┊ 0.00% ┊ table section headers
3 ┊ 0.00% ┊ memory section headers
3 ┊ 0.00% ┊ global section headers
3 ┊ 0.00% ┊ element section headers
2 ┊ 0.00% ┊ memory[0]
2 ┊ 0.00% ┊ "function names" subsection
2 ┊ 0.00% ┊ "function names" subsection
1693789 ┊ 100.00% ┊ Σ [203 Total Rows]
リリースビルドしたにも関わらずデバッグ情報がWasmに入っています。
wasm-bindgen-cliを通したあとのwasmにtwiggyを使ってみると次の通り。
twiggy top wasn_bindgen_test_bg.wasm
$ twiggy top .\.pkg\wasm_bindgen_test_bg.wasm
Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
6921 ┊ 26.25% ┊ "function names" subsection
4015 ┊ 15.23% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::malloc::hcec496a2198179fe
1185 ┊ 4.49% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::free::h5fba2897807212aa
1062 ┊ 4.03% ┊ core::str::count::do_count_chars::h8068e62995a060d4
979 ┊ 3.71% ┊ core::fmt::Formatter::pad_integral::ha4f8dd1eb5755fda
959 ┊ 3.64% ┊ core::fmt::Formatter::pad::hc84bfca380790d9b
881 ┊ 3.34% ┊ __rdl_realloc
770 ┊ 2.92% ┊ data[0]
664 ┊ 2.52% ┊ core::fmt::write::h3e26ed3eda73f0a3
623 ┊ 2.36% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::dispose_chunk::h15f89ab1d45de9ae
522 ┊ 1.98% ┊ alloc::fmt::format::h588637f2f2183a4d
385 ┊ 1.46% ┊ dlmalloc::Dlmalloc<A>::malloc::hecadd78677587853
354 ┊ 1.34% ┊ <alloc::string::String as core::fmt::Write>::write_char::hfcad3e975f1a678c
352 ┊ 1.34% ┊ alloc::string::String::push::he882a8f290dcb8c3
341 ┊ 1.29% ┊ core::fmt::num::imp::fmt_u64::h0c2fe44c27dae252
324 ┊ 1.23% ┊ compiler_builtins::mem::memcpy::h78a567d3a58ab6e5
322 ┊ 1.22% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::release_unused_segments::h4826643b506d455c
321 ┊ 1.22% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::unlink_large_chunk::h3cd39bebabb3864d
319 ┊ 1.21% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::insert_large_chunk::h0ab04c16e556807e
282 ┊ 1.07% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::take_box::h5fff44acdfbac4e7
257 ┊ 0.97% ┊ std::panicking::rust_panic_with_hook::he2a025723e105e28
198 ┊ 0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h2d7a97b6f3432e07
198 ┊ 0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h20a6726722873456
198 ┊ 0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h1397f88c4b936258
198 ┊ 0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h00dea0a6d40548b6
185 ┊ 0.70% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::get::h79854d279d39b63d
176 ┊ 0.67% ┊ alloc::raw_vec::finish_grow::h98b255e8c87ba6ac
176 ┊ 0.67% ┊ alloc::raw_vec::finish_grow::h7642e1a95a96c333
159 ┊ 0.60% ┊ std::panicking::begin_panic_handler::{{closure}}::hd9f8c213ec91b9d5
156 ┊ 0.59% ┊ greet
128 ┊ 0.49% ┊ core::result::unwrap_failed::h68fdaca771c68bb6
118 ┊ 0.45% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::init_top::h18355a6f078d958f
109 ┊ 0.41% ┊ std::alloc::default_alloc_error_hook::h0876b7eb4919815d
101 ┊ 0.38% ┊ <&mut W as core::fmt::Write>::write_fmt::he72a95b1e7bc46cb
101 ┊ 0.38% ┊ <&mut W as core::fmt::Write>::write_fmt::hcb1df0cddb10ef35
101 ┊ 0.38% ┊ custom section 'producers'
86 ┊ 0.33% ┊ core::fmt::Formatter::pad_integral::write_prefix::h9ddec898718cb90a
82 ┊ 0.31% ┊ <&mut W as core::fmt::Write>::write_str::h3169351e95b802c7
82 ┊ 0.31% ┊ <&mut W as core::fmt::Write>::write_str::hd4b6ba77fb1193cc
73 ┊ 0.28% ┊ core::panicking::panic::hc28e7cc2aa792341
71 ┊ 0.27% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::take_box::h8e753108593700f0
65 ┊ 0.25% ┊ alloc::raw_vec::capacity_overflow::h1de937e4490b6dee
64 ┊ 0.24% ┊ core::panicking::panic_fmt::hb02133958c1e7d35
62 ┊ 0.24% ┊ rust_begin_unwind
59 ┊ 0.22% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::alloc::h8b3509d622dedd6b
47 ┊ 0.18% ┊ __wbindgen_malloc
41 ┊ 0.16% ┊ dlmalloc::dlmalloc::Chunk::set_inuse::hd80515990c160bc8
40 ┊ 0.15% ┊ core::ptr::drop_in_place<std::error::<impl core::convert::From<alloc::string::String> for alloc::boxed::Box<dyn std::error::Error+core::marker::Sync+core::marker::Send>>::from::StringError>::h9ce0522b145fe6fa
40 ┊ 0.15% ┊ core::ptr::drop_in_place<std::panicking::begin_panic_handler::PanicPayload>::h636ad6d68e279e0d
40 ┊ 0.15% ┊ dlmalloc::dlmalloc::Segment::holds::h1a60be87238e9919
38 ┊ 0.14% ┊ rust_panic
37 ┊ 0.14% ┊ dlmalloc::dlmalloc::Chunk::set_free_with_pinuse::h64fe80d61b111714
36 ┊ 0.14% ┊ __wbindgen_realloc
35 ┊ 0.13% ┊ import wbg::__wbg_alert_0bebe9e6d7aece39
32 ┊ 0.12% ┊ dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse::hb9f654c37e5fb327
30 ┊ 0.11% ┊ elem[0]
30 ┊ 0.11% ┊ dlmalloc::dlmalloc::TreeChunk::leftmost_child::h8bd9454cc3d402c7
30 ┊ 0.11% ┊ <core::fmt::Error as core::fmt::Debug>::fmt::hb67b0fb623137665
28 ┊ 0.11% ┊ rust_oom
28 ┊ 0.11% ┊ core::option::Option<T>::unwrap::haa480509e27ff8fc
25 ┊ 0.09% ┊ core::option::Option<T>::unwrap::h3bbfb90b442ebef6
24 ┊ 0.09% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk::h11a8a5342df751be
22 ┊ 0.08% ┊ std::sys_common::backtrace::__rust_end_short_backtrace::h6efd730283875809
22 ┊ 0.08% ┊ <&T as core::fmt::Debug>::fmt::hea96acd558b28457
21 ┊ 0.08% ┊ export "__wbindgen_realloc"
21 ┊ 0.08% ┊ __rust_realloc
21 ┊ 0.08% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::get::h486eccde219d443e
20 ┊ 0.08% ┊ export "__wbindgen_malloc"
20 ┊ 0.08% ┊ dlmalloc::dlmalloc::leftshift_for_tree_index::h6fffd47072ccebc0
18 ┊ 0.07% ┊ dlmalloc::dlmalloc::align_up::hf1f4ea6608931a25
18 ┊ 0.07% ┊ <&T as core::fmt::Display>::fmt::hcaadeff9a1654879
18 ┊ 0.07% ┊ <&T as core::fmt::Display>::fmt::h8228500dd0a93de5
17 ┊ 0.06% ┊ dlmalloc::dlmalloc::left_bits::h4c3ee1c04a9d948c
17 ┊ 0.06% ┊ __rust_alloc
17 ┊ 0.06% ┊ dlmalloc::dlmalloc::Chunk::clear_pinuse::h28b4b6bfa0365301
16 ┊ 0.06% ┊ <&mut W as core::fmt::Write>::write_char::h735ba2e2255ac07c
16 ┊ 0.06% ┊ custom section 'producers' headers
15 ┊ 0.06% ┊ dlmalloc::dlmalloc::Chunk::cinuse::hfcc18d9ee069b807
15 ┊ 0.06% ┊ dlmalloc::dlmalloc::Chunk::inuse::h86972c896758fa35
15 ┊ 0.06% ┊ dlmalloc::dlmalloc::Segment::top::had8e50e872afff9d
15 ┊ 0.06% ┊ <&mut W as core::fmt::Write>::write_char::h7f2928ac137cbae7
15 ┊ 0.06% ┊ core::ops::function::FnOnce::call_once::h5753b14cff916f0e
15 ┊ 0.06% ┊ core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt::h6bf974e8791b3fa6
15 ┊ 0.06% ┊ <T as core::any::Any>::type_id::hf1eb4553966c7029
15 ┊ 0.06% ┊ <T as core::any::Any>::type_id::hf86124a39f31439b
15 ┊ 0.06% ┊ <T as core::any::Any>::type_id::hc91c1766c0a8e26b
14 ┊ 0.05% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk::h81fc9155883489ea
14 ┊ 0.05% ┊ code section headers
13 ┊ 0.05% ┊ __rust_dealloc
13 ┊ 0.05% ┊ dlmalloc::dlmalloc::Chunk::mmapped::h04354a447c7ef83b
12 ┊ 0.05% ┊ dlmalloc::dlmalloc::least_bit::h5164fc99df6558f5
12 ┊ 0.05% ┊ dlmalloc::dlmalloc::Chunk::size::ha342d078107e0f53
12 ┊ 0.05% ┊ dlmalloc::dlmalloc::Chunk::pinuse::h3e366cef7e528bba
12 ┊ 0.05% ┊ dlmalloc::dlmalloc::Segment::is_extern::h6fdd496f2978bb35
12 ┊ 0.05% ┊ dlmalloc::dlmalloc::Segment::sys_flags::h4d6b01219f9e07b9
12 ┊ 0.05% ┊ <str as core::fmt::Display>::fmt::he02814d332326528
12 ┊ 0.05% ┊ memcpy
11 ┊ 0.04% ┊ __rust_alloc_error_handler
11 ┊ 0.04% ┊ core::intrinsics::const_eval_select::hbff2fd2057209df4
11 ┊ 0.04% ┊ core::ops::function::FnOnce::call_once::h7538d6968a96c4c6
11 ┊ 0.04% ┊ alloc::alloc::handle_alloc_error::rt_error::h215dddd0f4495f99
11 ┊ 0.04% ┊ alloc::alloc::handle_alloc_error::h0693183370a7902c
11 ┊ 0.04% ┊ __rg_oom
11 ┊ 0.04% ┊ custom section 'name' headers
10 ┊ 0.04% ┊ type[13]: (i32, i32, i32, i32, i32, i32) -> i32
10 ┊ 0.04% ┊ __rdl_alloc
9 ┊ 0.03% ┊ type[12]: (i32, i32, i32, i32, i32) -> i32
9 ┊ 0.03% ┊ export "memory"
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::Chunk::plus_offset::hf594a71617f2958c
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::Chunk::minus_offset::ha660e14327ac3e4c
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::Chunk::to_mem::h4b386d4e48d965cf
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::Chunk::from_mem::h75b6b5095597031a
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::TreeChunk::next::h6a3f651c010e6975
9 ┊ 0.03% ┊ dlmalloc::dlmalloc::TreeChunk::prev::h052e4d2e0cbc3ff0
9 ┊ 0.03% ┊ core::panic::panic_info::PanicInfo::message::h102fddb6becb8eab
9 ┊ 0.03% ┊ core::panic::panic_info::PanicInfo::location::h5dfcade149d8a598
9 ┊ 0.03% ┊ core::panic::panic_info::PanicInfo::can_unwind::hf0853bc09675a7a1
8 ┊ 0.03% ┊ type[10]: (i32, i32, i32, i32) -> i32
8 ┊ 0.03% ┊ type[11]: (i32, i32, i32, i32, i32) -> nil
8 ┊ 0.03% ┊ global[0]
8 ┊ 0.03% ┊ export "greet"
8 ┊ 0.03% ┊ __rdl_dealloc
8 ┊ 0.03% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::page_size::h88a1bbbf4b8674f2
8 ┊ 0.03% ┊ wasm magic bytes
7 ┊ 0.03% ┊ type[8]: (i32, i32, i32) -> i32
7 ┊ 0.03% ┊ type[9]: (i32, i32, i32, i32) -> nil
7 ┊ 0.03% ┊ type[14]: (i64, i32, i32) -> i32
7 ┊ 0.03% ┊ type section headers
7 ┊ 0.03% ┊ import section headers
7 ┊ 0.03% ┊ table section headers
7 ┊ 0.03% ┊ memory section headers
7 ┊ 0.03% ┊ global section headers
7 ┊ 0.03% ┊ export section headers
7 ┊ 0.03% ┊ element section headers
7 ┊ 0.03% ┊ wasm_bindgen::__rt::malloc_failure::h8137027072480bce
7 ┊ 0.03% ┊ data section headers
6 ┊ 0.02% ┊ type[6]: (i32, i32) -> i32
6 ┊ 0.02% ┊ type[7]: (i32, i32, i32) -> nil
6 ┊ 0.02% ┊ dlmalloc::dlmalloc::Chunk::fencepost_head::h343fc8d31cab4021
6 ┊ 0.02% ┊ dlmalloc::dlmalloc::Chunk::mem_offset::hb26f0a8f126c0579
6 ┊ 0.02% ┊ dlmalloc::dlmalloc::TreeChunk::chunk::h9cbb25ca6296593a
6 ┊ 0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::remap::h0979387267a4a643
6 ┊ 0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free_part::hef5dee6eb24bcc8c
6 ┊ 0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free::h0aa881b9e76b9b02
6 ┊ 0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::can_release_part::hc2a2319ea9025de0
5 ┊ 0.02% ┊ type[3]: (i32) -> i32
5 ┊ 0.02% ┊ type[4]: (i32) -> i64
5 ┊ 0.02% ┊ type[5]: (i32, i32) -> nil
5 ┊ 0.02% ┊ std::process::abort::hbba08b3d6df850f8
5 ┊ 0.02% ┊ __rust_start_panic
4 ┊ 0.02% ┊ type[1]: () -> i32
4 ┊ 0.02% ┊ type[2]: (i32) -> nil
4 ┊ 0.02% ┊ table[0]
4 ┊ 0.02% ┊ core::ptr::drop_in_place<&mut std::io::Write::write_fmt::Adapter<alloc::vec::Vec<u8>>>::ha5213606bfbb1ca2
4 ┊ 0.02% ┊ core::ptr::drop_in_place<&u8>::h52ad2d112c7e2ce3
4 ┊ 0.02% ┊ core::ptr::drop_in_place<&core::iter::adapters::copied::Copied<core::slice::iter::Iter<u8>>>::h0e2bcd53588f6395
3 ┊ 0.01% ┊ type[0]: () -> nil
2 ┊ 0.01% ┊ memory[0]
26366 ┊ 100.00% ┊ Σ [158 Total Rows]
デバッグ情報が消えました。
上位に残っているのは関数名のセクションです。
さらにwasm-optで最適化をかけたあとでは次のようになります。
twiggy top opt-wasm.wasm
$ twiggy top .\.pkg\opt-wasm.wasm
Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼──────────────────────────────────────────
4207 ┊ 24.98% ┊ code[0]
1904 ┊ 11.30% ┊ code[2]
1028 ┊ 6.10% ┊ code[51]
885 ┊ 5.25% ┊ code[1]
770 ┊ 4.57% ┊ data[0]
731 ┊ 4.34% ┊ code[15]
723 ┊ 4.29% ┊ code[37]
641 ┊ 3.81% ┊ code[3]
592 ┊ 3.51% ┊ code[4]
366 ┊ 2.17% ┊ code[5]
351 ┊ 2.08% ┊ code[49]
349 ┊ 2.07% ┊ code[42]
315 ┊ 1.87% ┊ code[57]
313 ┊ 1.86% ┊ code[7]
305 ┊ 1.81% ┊ code[24]
295 ┊ 1.75% ┊ code[6]
274 ┊ 1.63% ┊ code[10]
268 ┊ 1.59% ┊ code[9]
187 ┊ 1.11% ┊ code[11]
187 ┊ 1.11% ┊ code[12]
175 ┊ 1.04% ┊ code[13]
154 ┊ 0.91% ┊ code[14]
113 ┊ 0.67% ┊ code[8]
105 ┊ 0.62% ┊ code[17]
101 ┊ 0.60% ┊ custom section 'producers'
91 ┊ 0.54% ┊ code[16]
91 ┊ 0.54% ┊ code[18]
80 ┊ 0.47% ┊ code[19]
77 ┊ 0.46% ┊ code[20]
76 ┊ 0.45% ┊ code[21]
70 ┊ 0.42% ┊ code[22]
65 ┊ 0.39% ┊ code[23]
44 ┊ 0.26% ┊ code[25]
41 ┊ 0.24% ┊ code[26]
37 ┊ 0.22% ┊ code[30]
35 ┊ 0.21% ┊ import wbg::__wbg_alert_0bebe9e6d7aece39
34 ┊ 0.20% ┊ code[28]
32 ┊ 0.19% ┊ code[27]
32 ┊ 0.19% ┊ code[29]
32 ┊ 0.19% ┊ code[31]
30 ┊ 0.18% ┊ elem[0]
30 ┊ 0.18% ┊ code[35]
27 ┊ 0.16% ┊ code[32]
27 ┊ 0.16% ┊ code[56]
24 ┊ 0.14% ┊ code[34]
22 ┊ 0.13% ┊ code[39]
21 ┊ 0.12% ┊ export "__wbindgen_realloc"
21 ┊ 0.12% ┊ code[43]
20 ┊ 0.12% ┊ export "__wbindgen_malloc"
20 ┊ 0.12% ┊ code[33]
18 ┊ 0.11% ┊ code[36]
18 ┊ 0.11% ┊ code[40]
17 ┊ 0.10% ┊ code[38]
16 ┊ 0.09% ┊ code[50]
15 ┊ 0.09% ┊ code[44]
15 ┊ 0.09% ┊ code[48]
15 ┊ 0.09% ┊ code[62]
15 ┊ 0.09% ┊ code[63]
15 ┊ 0.09% ┊ code[64]
14 ┊ 0.08% ┊ code[47]
13 ┊ 0.08% ┊ code[46]
12 ┊ 0.07% ┊ code[45]
12 ┊ 0.07% ┊ code[52]
12 ┊ 0.07% ┊ code[53]
12 ┊ 0.07% ┊ code[54]
12 ┊ 0.07% ┊ code[55]
12 ┊ 0.07% ┊ custom section 'producers' headers
10 ┊ 0.06% ┊ code[41]
9 ┊ 0.05% ┊ export "memory"
9 ┊ 0.05% ┊ code[58]
9 ┊ 0.05% ┊ code[59]
9 ┊ 0.05% ┊ code[60]
9 ┊ 0.05% ┊ code[61]
8 ┊ 0.05% ┊ type[8]: (i32, i32, i32, i32, i32) -> nil
8 ┊ 0.05% ┊ type[10]: (i32, i32, i32, i32) -> i32
8 ┊ 0.05% ┊ global[0]
8 ┊ 0.05% ┊ export "greet"
8 ┊ 0.05% ┊ wasm magic bytes
7 ┊ 0.04% ┊ type[2]: (i32, i32, i32) -> i32
7 ┊ 0.04% ┊ code section headers
6 ┊ 0.04% ┊ type[0]: (i32, i32) -> i32
6 ┊ 0.04% ┊ type[5]: (i32, i32, i32) -> nil
5 ┊ 0.03% ┊ type[1]: (i32, i32) -> nil
5 ┊ 0.03% ┊ type[3]: (i32) -> i32
5 ┊ 0.03% ┊ type[6]: (i32) -> i64
5 ┊ 0.03% ┊ code[65]
4 ┊ 0.02% ┊ type[4]: (i32) -> nil
4 ┊ 0.02% ┊ type[7]: () -> i32
4 ┊ 0.02% ┊ table[0]
4 ┊ 0.02% ┊ data section headers
3 ┊ 0.02% ┊ type[9]: () -> nil
3 ┊ 0.02% ┊ type section headers
3 ┊ 0.02% ┊ import section headers
3 ┊ 0.02% ┊ table section headers
3 ┊ 0.02% ┊ memory section headers
3 ┊ 0.02% ┊ global section headers
3 ┊ 0.02% ┊ export section headers
3 ┊ 0.02% ┊ element section headers
2 ┊ 0.01% ┊ memory[0]
16844 ┊ 100.00% ┊ Σ [99 Total Rows]
関数名のセクションも消えて、だいぶファイルサイズが最適化されていそうなことがわかります。
Trunk
Trunkはビルドツールの一種です。
RustとWasmを組み合わせて使うように作られていますが、Wasmの他にSassからCSSへのコンバートなどWebアプリを作るのに必要なビルド機能もいくつか対応しています。
現時点ではRustで書いたWasmをnpmパッケージ等にラップすることなく直接HTML上で実行したい場合、Trunkが最速で実行できると思います。
エントリーポイントとなるindex.html
にRustのWasmをビルドして最適化処理をかけたものを読み込む処理を埋め込み、その他リソースの処理なども行った上で、開発用サーバーを立ててくれてブラウザの自動リロードにも対応してくれます。
次項で実際にTrunkを使っていきます。
Trunkを使ってみる
まずはRustのインストールを済ませておいてください。
次にcargp install
でTrunkをインストールします。
$ cargo install --locked trunk
次にこのような空っぽのhtmlファイルをindex.html
という名前でCargo.tomlの隣に配置します。
<!DOCTYPE html>
<html>
<head></head>
</html>
このファイルがエントリーポイントとなります。
次にいくつかのパッケージを追加します。
cargo-edit
が入っている場合は次のコマンドを打ちます。
$ cargo add log wasm-logger
logはRustの一般的に使われているロギングのライブラリで、wasm-loggerはconsole.logにlogクレートのログの内容を流してくれるものです。
次にmain.rsに次のように書きます。
pub fn main() {
wasm_logger::init(wasm_logger::Config::default());
log::debug!("Hello, world!");
}
Trunkがwasm-bindgenとのつなぎ込みもやってくれるようなので、main関数を書くだけで良いです。
main関数はWasmをロードしたあとに勝手に走るようになっているようです。
ここまで書いたら次のコマンドを実行します。
$ trunk serve
これでビルドが走りサーバーが立ち上がります。
http://127.0.0.1:8080を開いて開発者ツールをみると次のようにHello, Worldが表示されていました。
wasm-optの最適化オプションを付けるにはindex.html
に次のような指定をします。
<!DOCTYPE html>
<html>
<head>
<link data-trunk rel="rust" data-wasm-opt="z">
</head>
</html>
trunk serve --release
あるいはtrunk build --release
とすることでリリースモードで実行すると、wasm-optが実行され、Wasmのサイズが小さくなって配信に向いた形になります。
おわりに
RustでWasmを書く際に使える周辺ライブラリをまとめ、その後Trunkで実際にWasmを作成し動かすところまでやりました。
今回の記事では試しませんでしたが、JavaScriptとWasmの間でのやり取りもwasm-bindgenによってだいぶ書きやすくなっています。
次回の記事ではYewというWasm用ライブラリをTrunkを使ってビルドしてみたいと思います。
Discussion
とても参考になりました!ありがとうございます✨