Lua + FFI vs. Javascript

スモールピック



この短い記事は記事を装っていません。



前回は、例として単純なレイトレーサーを使用して、さまざまなブラウザーでLuaJIT 2.0 Beta 5とJavaScriptを比較しました。 比較結果:ChromeのJavaScriptは20,000 RPSを獲得して1位になり、LuaJIT-5,000 RPSと最下位になりました。



LuaJIT 2.0 Beta 6のリリースで状況が変わりました。LuaはChromeの上に簡単に登場しました。 それがどうなったか見てみましょう。







数字を入力する必要がある大きな配列があると想像してください。 これをどうやってやるの? Luaの実装例を次に示します。



a = {} for i = 1, n do a[i] = i*i - 0.5 end
      
      







nが大きい場合、これは非常にゆっくりと動作します。Luaは事前に配列のサイズを認識していないため、この配列のサイズを動的に大きくする必要があります。 Luaは、配列のインデックスが1..nの範囲の数値であり、値が整数であることすら知らないため、ある日、配列に次のように書き込むときに最悪のケースに依存する必要があります。



 a['qqq'] = {red = 1, green = 0.5, blue = 0.8}
      
      







この汎用性により、プログラムの速度が低下します。 「double a [n]」という形式の配列があることを、何らかの形でLuaに伝えたいと思います。 これを標準のLuaツールで行うことはできませんが、Luaに拡張機能を追加することができます-これにより言語が可能になり、必要なものを取得できます。 この拡張機能はFFIと呼ばれます。 配列の問題を解決する方法は次のとおりです。



 ffi = require'ffi' a = ffi.new('double[?]', 1 + n) for i = 1, n do a[i] = i*i end
      
      







この単純なコード変更により、速度が何倍も向上し、メモリが大幅に削減されます。 レイトレーサーに必要なもの。



以前のレイトレーサーは、3つのフィールドを持つ小さなテーブルである花で構成されるテーブルをメモリに保持していました。 各ピクセルを介して光線が発射され、色が計算され、この色がテーブルに落ちました。 次のようになりました。



 pixels = {} for x = 1, width do for y = 1, height do local color = raytrace(x, y) pixels[y*width + x] = color end end
      
      







動作中、このピクセルテーブルが大きくなり、新しい要素を追加する時間が長くなり、レイトレーサーの速度が低下しました。 結果は5,000 RPS(1秒あたりの光線数)と最後の場所です。



FFIの登場により、事前にメモリを割り当てて、ピクセルテーブルを配列として表すことが可能になりました。 アルゴリズムは次のようになりました。



 ffi = require'ffi' pixels = ffi.new('float[?]', width*height*3) i = 0 for y = 1, height do for x = 1, width do local color = raytrace(x, y) pixels[i + 0] = color[1] pixels[i + 1] = color[2] pixels[i + 2] = color[3] i = i + 3 end end
      
      







コードは以前よりも少し長くなりましたが、他の場所ではコードが簡素化されています。たとえば、そのような配列をBMPファイルに保存する方が簡単です。 この単純な最適化は3つのことを行います。



  1. メモリの量は25メガバイトに減り、操作中に増加しません。
  2. レイトレーサーの速度は、結果の画像のサイズに依存しません。
  3. 速度が40,000 RPSに増加




比較のため:前の比較の最良の結果-JavaScript + Chrome-20,000 RPSを受信し、150 MBのメモリを消費しました。



以下のテスト結果は、以前の比較の一部です。 Raytraceプログラムは、各ピクセルに3つのビームを通過させることにより、同じシーンを1000×1000ピクセルの画面に送信しました。



ルアジット 40,000 RPS 25 Mb
クロム 20,400 RPS 150 Mb
オペラ 15,700 RPS
Firefox 9,300 RPS
探検家 9,000 RPS




Luaについて簡単に書いたと言って、彼はベクトルの各操作(加算、数値の乗算)で結果を持つ新しいベクトルを作成します。 常に作成されるこのベクターは、ガベージコレクターの役割を果たします。 余分なベクトルを作成しない場合、レイトレーサーの速度はさらに向上します。



私が話したレイトレーサーはここにある 。 コマンド「luajit main.lua」を実行します。 luajitバージョンは少なくとも2.0 Beta 6です。



All Articles