WebGL-Native: Unityでかすぎ問題
prev: https://zenn.dev/okuoku/scraps/f7ac420090e881
next: https://zenn.dev/okuoku/scraps/2ebc38f03786f4
でかい
前回までで、Node.JSのWebAssembly実装を使わずにEmscriptenでビルドしたWebGLコードが動作できるようになった。Unityは使っているEmscriptenがちょっと古いので追加の調整は必要だけど。
というわけで、Unityのコードを wasm2c
してコンパイルしてみたところ
... out of memory。。
まぁ200MiB以上あるもんな。。
CygwinのGCC 9.3で処理してみたところ、最適化なしでも10分以上コンパイルに掛かり、10GiB以上のRAMを消費していた。
$ time cc -c -o temp.o dll.c
real 12m40.150s
user 12m28.640s
sys 0m9.545s
これを何とかしないといけない。ちょっと思いつくのは、
- 一旦LLVM中間コードを経由してビルドする 。基本的にclangはコンパイル時にメモリを解放しないので明示的に処理を分割することで多少は省メモリにできるのではないか説。clangは.c入力をLLVM bitcodeで出力する機能があるためそれを利用できる。
- Binaryenで再最適化する 。Emscriptenは自身のオプティマイザ類をBinaryen https://github.com/WebAssembly/binaryen として分離していて、Dead code eliminationのような通常のコンパイラで実施している最適化はこちらでも実施できる。これによりコード量を減らせないだろうか。
-
MinGWを使って.aにしておく 。まぁ10分掛かるけどコンパイルはできるので
gcc
であるMinGWを使えばとりあえず先に進めなくはない。。 - あきらめてインタプリタを先に試す 。ここまででダメだったらwasm3とかのインタプリタを先に試すことにしよう。。
予備実験: CygwinのLLVMで試してみる
とりあえず適当にCygwinのLLVM8で試してみる。
まずbitcodeへの出力。これは.c のAST → LLVM IRへの直接的な変換なので、そこまで時間は掛からない。(ASTレベルの最適化も無くはないが大したことはしない)
$ time clang -c -emit-llvm -o out.bc dll.c
real 1m24.247s
user 1m20.124s
sys 0m3.858s
このファイルは736万行あるので、毎秒9万行は処理できていることになる。
$ wc -l dll.c
7363483 dll.c
次にアセンブリの出力:
$ time llc -O0 -filetype=obj -o out.o out.bc
real 5m16.930s
user 5m12.984s
sys 0m3.437s
5分..うーむそんなもんなのかな。。とりあえずコレでワークフローに組み込んでみる。
Visual Studioには llc が付いてこない問題
... Visual StudioにはLLVM中間言語のコンパイラである llc
が付属してこないようだ。。
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.8.4
** Copyright (c) 2020 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional>where clang
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\bin\clang.exe
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional>where llc
情報: 与えられたパターンのファイルが見つかりませんでした。
WebAssemblyのリンカである wasm-ld
は付いてくるのに。。(当然Win32はWebAssemblyには対応してないので単にストレージの無駄となる -- 好意的に言えば VisualStudioにはWebAssemblyのツールチェインが付属している とも言えるが。。例えば 以前のDOOMのような用途 であれば活用できる。)
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional>where wasm-ld
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\Llvm\x64\bin\wasm-ld.exe
... まぁ clang は言語として .bc の拡張子を認識するので、単に llc
を clang
に置き換えれば同じことができる。
$ time clang -O0 -c -o out.o out.bc
real 5m20.757s
user 5m16.732s
sys 0m3.357s
Visual StudioのIDEからビルドした場合だけout of memoryになる
[1/4] WASM: Translating .c => LLVM
FAILED: dll_bc.bc
cmd.exe /C "cd /D C:\cygwin64\home\oku\repos\cwgl\jstestapp\dlltest && clang -c -emit-llvm -O0 -o C:/cygwin64/home/oku/repos/cwgl/jstestapp/dlltest/out/build/x64-Debug/dll_bc.bc dll.c"
C:\cygwin64\home\oku\repos\cwgl\jstestapp\dlltest\out\build\x64-Debug\EXEC : LLVM error : out of memory
Stack dump:
0. Program arguments: clang -c -emit-llvm -O0 -o C:/cygwin64/home/oku/repos/cwgl/jstestapp/dlltest/out/build/x64-Debug/dll_bc.bc dll.c
1. <eof> parser at end of file
2. Per-file LLVM IR generation
C:\cygwin64\home\oku\repos\cwgl\jstestapp\dlltest\out\build\x64-Debug\EXEC : 3. LLVM error : out of memory
ninja: build stopped: subcommand failed.
意味わかんねぇ挙動だ。。
成功時のピーク消費量は4.8GiBで、out of memoryで落ちるときはもっと少いため、VisualStudioがビルドプロセスをCreateProcessする際になんらかの制限を入れている気がする。
まぁ生成コードをIDEで編集することは無いだろうからとりあえずビルドはコマンドラインでいいや。。
CMake側の実装
単に add_custom_command
でOK。 clang
の場所は調整できるようにした方が良いかな。。
本当にclangが必要なのはココだけだけどclangのCOFFとMSVCのCOFFがちゃんとリンクできるか自信無いので全体をclangでビルドするのはそのままにした。