Open5

WebGL-Native: Unityでかすぎ問題

okuokuokuoku

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

これを何とかしないといけない。ちょっと思いつくのは、

  1. 一旦LLVM中間コードを経由してビルドする 。基本的にclangはコンパイル時にメモリを解放しないので明示的に処理を分割することで多少は省メモリにできるのではないか説。clangは.c入力をLLVM bitcodeで出力する機能があるためそれを利用できる。
  2. Binaryenで再最適化する 。Emscriptenは自身のオプティマイザ類をBinaryen https://github.com/WebAssembly/binaryen として分離していて、Dead code eliminationのような通常のコンパイラで実施している最適化はこちらでも実施できる。これによりコード量を減らせないだろうか。
  3. MinGWを使って.aにしておく 。まぁ10分掛かるけどコンパイルはできるので gcc であるMinGWを使えばとりあえず先に進めなくはない。。
  4. あきらめてインタプリタを先に試す 。ここまででダメだったらwasm3とかのインタプリタを先に試すことにしよう。。
okuokuokuoku

予備実験: 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分..うーむそんなもんなのかな。。とりあえずコレでワークフローに組み込んでみる。

okuokuokuoku

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 の拡張子を認識するので、単に llcclang に置き換えれば同じことができる。

$ time clang -O0 -c -o out.o out.bc

real    5m20.757s
user    5m16.732s
sys     0m3.357s
okuokuokuoku

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で編集することは無いだろうからとりあえずビルドはコマンドラインでいいや。。