LuneScript のトランスコンパイル時間を 478 パーセント改善した件

Page content

前回から引き続き 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 に変換したファイルとなります。