WebAssemblyをnginxサーバーで動かす。jsとwasmで実行時間比較

## はじめに
[WebAssembly](https://developer.mozilla.org/ja/docs/WebAssembly)が注目されているので使ってみました。環境は`Ubuntu 18.04`です。- [Interacting with code — Emscripten 1.39.8 documentation](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html)を主な参考にしました。


## [Emscripten](https://emscripten.org/index.html)のインストール
`sudo apt install emscripten`でいけるかなと思ったのですが、`emcc`でコンパイルしようとすると

```zsh
emcc sqrt.cpp -o function.html -s EXPORTED_FUNCTIONS='["_int_sqrt"]' -s EXTRA_EX
PORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
WARNING  root: LLVM version appears incorrect (seeing "(/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project", expected "3.4")
INFO     root: (Emscripten: Running sanity checks)
CRITICAL root: Cannot find /home/endo/Documents/workdir/emsdk/upstream/bin/lli, check the paths in ~/.emscripten
```

とよくわからないエラーが出たので[公式](https://emscripten.org/docs/getting_started/downloads.html)に従って

```zsh
# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk
# Fetch the latest version of the emsdk (not needed the first time you clone)
git pull

# Download and install the latest SDK tools.
./emsdk install latest

# Make the "latest" SDK "active" for the current user. (writes ~/.emscripten file)
./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
source ./emsdk_env.sh
```

とやりました。シェルに`fish`を使ってたのが問題かもしれませんが未検証です。

## C++のファイル

```cpp:loop.cpp
extern "C" {

int loop(int num) {
  for (int n0 = 0; n0 < num; n0++) {
    for (int n1 = 0; n1 < num; n1++) {
      for (int n2 = 0; n2 < num; n2++) {
        if (n0 + n1 + n2 == (num - 1) * 3) {
          return n0;
        }
      }
    }
  }
  return 0;
}
}
```
とりあえず重い処理をさせたかったので計算量$O(n^3)$の処理を書きました。

```zsh
emcc loop.cpp -o loop.html -s EXPORTED_FUNCTIONS='["_loop"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
```
でコンパイルします。

`loop.html`、`loop.js`、`loop.wasm`が今回生成としてファイルです。

## html (JavaScript)
`loop.html`は無視してコードを書きます。`WebAssembly`を利用した場合と`JavaScript`で同じ処理を書いた場合で実行時間を比較できるようにしてみました。

```html:loop.html
<button id="loopc">loop with C</button>
<button id="loopj">loop with js</button>

<script>
  // WebAssemblyを使う。
  let loopcBtn = document.getElementById("loopc");
  let loopc;
  Module = {
    onRuntimeInitialized: function() {
      loopc = Module.cwrap("loop", "number", [
        "number",
      ]);
    },
  };
  loopcBtn.addEventListener("click", function() {
    const startTime = performance.now();
    console.log(loopc(2000));
    const endTime = performance.now();
    console.log(endTime - startTime);
  });
  
  // javascriptで同じ処理をしてみる (比較用)
  let loopjBtn = document.getElementById("loopj");
  function loopj(num) {
    for (let n0 = 0; n0 < num; n0++) {
      for (let n1 = 0; n1 < num; n1++) {
        for (let n2 = 0; n2 < num; n2++) {
          if (n0 + n1 + n2 === (num - 1) * 3) {
            return n0;
          }
        }
      }
    }
    return 0;
  }
  
  
  loopjBtn.addEventListener("click", function() {
    const startTime = performance.now();
    console.log(loopj(2000));
    const endTime = performance.now();
    console.log(endTime - startTime);
  });
</script>

<script src="./loop.js"></script>
```


## nginxの設定

[Incorrect response MIME type. Expected 'application/wasm' エラーの 対応 - Qiita](https://qiita.com/kamykn/items/0bd8b1dfb342ab478e4a)の記事を参考にさせていただきました。[nginx連載3回目: nginxの設定、その1 - インフラエンジニアway - Powered by HEARTBEATS](https://heartbeats.jp/hbblog/2012/02/nginx03.html)を参考にしながら、`/etc/nginx/mime.types`に

```
application/wasm                                wasm  
```
を書き足してnginxを再起動します。

## 実行結果
||実行時間|
|:--|--:|
|wasm|17721.55 [ms]|
|js|10688.32 [ms]|

**wasmのほうが今回は時間がかかりました。**

[WebAssemblyとは？〜実際にC言語をブラウザで動かす〜【2019年6月版】 - Qiita](https://qiita.com/umamichi/items/c62d18b7ed81fdba63c2)に書いてあるように実行時間が短くなるわけではなくファイルサイズが小さくなってロード時間が短くなるのが恩恵なので妥当な結果ではありますが、ちょっと残念ではあります。なお、実行したブラウザはGoogle Chromeのversion `80.0.3987.122`です。

## 参考にさせていただいたリンク集
- [ネイティブアプリ並みのパフォーマンス！WebAssemblyでフロントエンド開発が変わる | スターフィールド株式会社](https://sterfield.co.jp/designer/webassembly%E3%81%A7%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E9%96%8B%E7%99%BA%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%8B/)
- [C/C++からWebAssemblyにコンパイルする - WebAssembly | MDN](https://developer.mozilla.org/ja/docs/WebAssembly/C_to_wasm)
- [Download and install — Emscripten 1.39.8 documentation](https://emscripten.org/docs/getting_started/downloads.html)
- [Incorrect response MIME type. Expected 'application/wasm' エラーの 対応 - Qiita](https://qiita.com/kamykn/items/0bd8b1dfb342ab478e4a)
- [nginx連載3回目: nginxの設定、その1 - インフラエンジニアway - Powered by HEARTBEATS](https://heartbeats.jp/hbblog/2012/02/nginx03.html)
- [WebAssemblyとは？〜実際にC言語をブラウザで動かす〜【2019年6月版】 - Qiita](https://qiita.com/umamichi/items/c62d18b7ed81fdba63c2)
- [Interacting with code — Emscripten 1.39.8 documentation](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html)