WebAssemblyとJavaScriptの最適化による処理速度を比較してみる

# はじめに
[前回](https://qiita.com/mink0212/items/c7fc8d1e7c036b706544)のコメントで「サンプルが簡単すぎてCの最適化が早いのは当然」や「JavaScriptも最適化がある」と言ったことを教えてもらえたので再度比較してみました。

# 環境
 - windows 10
 - python:3.6.5
 - emcc:1.39.16
 - clang:11.0.0

# 実験ブラウザ
 - Google Chrome:83.0.4103.106
  
# 純粋なループの比較
前回と同様にそれぞれの中でループをさせてみました。JavaScriptの最適化はprepackとClosure Compilerの2つを使いました。

## C/C++ファイルの作成とコンパイル
前回と全く同じなので省略します。

## htmlの作成する
前回とほぼ同じなので省略します。

## JavaScriptの作成と最適化
### 最適化用JavaScriptの作成
今回は最適化するためにループ部分だけ別ファイルにします。

``` jsmod.js

function loop_func_ori(){
    var count = 0;
    for(var i = 0; i < 100000000; i++){
        count = count + 1;
    }
    return count;
}
```

### 最適化ツール(prepack)のインストール
npmを使用してprepackをインストールします。

```

npm install prepack 
```

インストールしたフォルダ内のnode_modulesにprepackが追加されています。

### JavaScriptの最適化(prepack)
prepackコマンドを使用して最適化を行います。

```

>.\node_modules\.bin\prepack jsmod.js --out jsmod-prepa.js
Prepacked source code written to jsmod-prepa.js.
```

--outで指定したファイルに最適化後のJavaScriptができます。

``` jsmod-prepa.js

var loop_func;
(function () {
  var _$0 = this;

  var _1 = function () {
    var count = 0;

    for (var i = 0; i < 100000000; i++) {
      count = count + 1;
    }

    return count;
  };

  _$0.loop_func = _1;
}).call(this);
```

### JavaScriptの最適化(Closure Compiler)
Closure Compilerは[公式](https://closure-compiler.appspot.com/home)から最適化を行います。

``` jsmod-clo.js

function loop_func_clo(){for(var a=0,b=0;1E8>b;b++)a+=1;return a};
```

最適化しましたが、両方ともあまり処理が短縮されていないように感じます。

## 実行
サーバを再起動して上のhtmlを実行します。

|回数|JavaScript|JavaScript prepack最適化あり|JavaScript Closure Compiler最適化あり|C++最適化なし|C++最適化01|C++最適化02|C++最適化03|
|---|---|---|---|---|---|---|---|
|1|84.914|82.774|82.875|426.709|0.0699|0.0949|0.0499|
|2|83.609|82.669|82.170|421.660|0.0449|0.0500|0.0550|
|3|54.994|55.779|55.080|422.435|0.0499|0.0350|0.0499|
|4|54.495|57.089|55.375|429.959|0.0450|0.2099|0.0599|
|5|54.455|55.075|55.044|421.464|0.0299|0.0399|0.0500|

結果を見ると、予想通りJavaScriptの最適化はあまり早くなっていないことがわかりました。
それ以外は、前回と同様にC++の方が早く、C++は最適化を強くするたびに処理速度が速くなっています。
JavaScriptの最適化はC++の最適化とは異なり、抽象化の解消や関数の事前実行など若干使い方が異なるので早くならなかったのかなと思います。

一応以下を最適化すれば処理時間が短くなりそうなのですが、最適化がいつまでたっても終わらないので諦めました。

``` jsmod2.js

function loop_func_ori(){
    var count = 0;
    for(var i = 0; i < 100000000; i++){
        count = count + 1;
    }
    return count;
}

var i = loop_func_ori()
```

# 引数のある関数の比較
C++の引数のある関数をJavaScriptから呼び出した時の速度を試してみました。

## C/C++ファイルの作成
引数のあるC++関数をJavaScriptから呼び出す方法は[前に書いた独自のC ++関数の連携](https://qiita.com/mink0212/items/d5947ec0d619d6d74eb2#%E7%8B%AC%E8%87%AA%E3%81%AEc%E9%96%A2%E6%95%B0%E3%81%AE%E9%80%A3%E6%90%BA)に引数を追加するだけです。

``` cmain.cpp

#include <emscripten/emscripten.h>

extern "C" {
    int EMSCRIPTEN_KEEPALIVE loop_func(int n) {
        int count = 0;
        while(true){ 
            count = count + 1;
            if (n == 0){
                break;
            }
            n = n - 1;
        }
        return count;
    }
}
```

## wasmを呼び出すhtmlを作成する
htmlはほぼ同じなので省略します。

## JavaScriptの作成と最適化
基本は先ほどと同じです。今回は関数の処理が変わるため、そこだけ変更しています。
各関数に与えている整数は1000000000にしています。

``` jsmod.js

function loop_func_js_ori(n){
    var count = 0;
    while(true){
        count = count + 1
        if (n == 0){
          break;
        }
        n = n -1;
    }
    return count;
}
```

## 実行
サーバを再起動して上のhtmlを実行します。

|回数|JavaScript|JavaScript prepack最適化あり|JavaScript Closure Compiler最適化あり|C++最適化01|C++最適化02|C++最適化03|
|---|---|---|---|---|---|---|
|1|672.230|672.750|672.200|0.0600|0.0549|0.0999|
|2|669.505|675.559|674.194|0.0450|0.0499|0.0550|
|3|665.550|669.945|678.404|0.0550|0.0350|0.0450|
|4|670.449|678.560|698.879|0.0450|0.0550|0.0399|
|5|672.009|671.985|720.339|0.0550|0.0400|0.0350|

結果を見ると単純なループと同じようにC++の方がJavaScriptより速いことがわかりました。これはループでもわかっていたため、単純にそうなんだーぐらいの感想でした。

# おわりに
コメントを受けて他のパターンを試してみました。意外！と思えなかったので、個人的にはあまり面白くない結果でした。今回は、JavaScriptの最適化に不利な処理での比較になってしまったためJavaScriptの最適化はあまりすごくないイメージができてしまいましたが、大きなJavaScriptを最適化すれば意味のあるものになると思います。JavaScriptの最適化に有利な方法を思いついたら比較してみようと思います。実験の結果では前回と感想は変わりませんでした。