LuneScript のトランスコンパイル時間を 478 パーセント改善した件
前回から引き続き LuneScript のトランスコンパイル時間短縮を行なっています。
今回の時間短縮は以下の通りです。
改善前(lua) | 改善後(go) | 参考 (lua batch) | 参考 (luajit) |
---|---|---|---|
20.65 sec | 4.32 sec | 21.90 sec | 21.56 sec |
この表の通り、 (/ 20.65 4.32) 4.780092592592592 ≒ 478% 改善しています。
以降では、今回の LuneScript 性能向上の実現方法について説明します。
一括処理
従来は、複数ある .lns ファイルを一つずつ処理するために、 LuneScript をファイル数分実行していました。
今回は、複数ある .lns ファイル全てを 一回の LuneScript の起動で処理するように対応しました。
これによって、次の効果が得られていると思います。
- データがメモリ上にキャッシュされ、一部の解析が不要になった
- 複数回の起動終了処理に掛る時間が、 1 度だけになった
ある意味で当たり前といえば当たり前の結果ですが、 これを実現するには、最低限リエントラントにする必要があり、 意外なところに落とし穴があったりするものです。
まぁ今回は事前に準備をしておいたので、 解析処理の繰り返し制御部分を追加しただけで動いたのですが。
上の表を見ると分かりますが、 同じ一括処理を Lua 版 LuneScript で実行すると 逆に遅くなるという結果になりました。
なお、今回の対応後の goprof の結果を見ると、 import 処理が思った以上に短縮されていないことが分かりました。
この原因は、 トランスコンパイルするファイルが異なる場合、 以前別のファイルで import した型も再度登録処理しているため、 想像以上に時間がかかっているようです。
これは、型の ID がファイル毎にシーケンシャルになっていることを前提に処理しているため、 必要な処理です。 この import 処理を高速化するには、 「型の ID がファイル毎にシーケンシャルになっている」ことを期待しないで 処理できるように対応する必要があります。
これはちょっと面倒そうです。
ただこれを改善すると、更に 1 秒近く改善できそうなので対応する価値はあります。
気が向いたら対応しようと思います。
なお今回の一括処理対応では、指定されたファイルをシーケンシャルに処理します。 個々のファイルのトランスコンパイル処理を並列化していません。
LuneScript のセルフホスティングのソースでは、 ほとんどのファイルが片方向リストの様に import しているため、 並列に処理することが出来ません。 前のファイルを処理しないと、次のファイルが処理できない状態です。
よって、並列化されないことはほとんどパフォーマンスに影響しません。 しかし、プロジェクトによっては並列化の影響が大きいこともあります。
その場合は、今回の一括処理すると遅くなる可能性があります。
使用方法
LuneScript のトランスコンパイル対象ファイル指定のオプションに @- を指定し、 トランスコンパイル対象のファイルパスを一行毎 stdin に入力するだけです。
なお、一点注意があります。
一括処理している際の –depends オプションは、 ディレクトリ指定として扱います。
つまり従来のファイル毎の LuneScript では、 –depends オプションは、 Make 用依存ファイルの出力先ファイルパスでしたが、 一括処理時の –depends オプションは依存ファイルの出力先ディレクトリパスになります。 そして、実際に出力さられるファイルは、その出力先ディレクトリパスに トランスコンパイル対象のファイルパスの .lns を .d に変換したファイルとなります。