BlogKLabは、多くのスマートフォン向けゲームを開発・提供しています。スマートフォン向けゲームの開発と運用は、Webソーシャルゲームと比べて格段に複雑で、またコンシューマゲーム開発とも異なったノウハウが求められる領域もあります。このブログでは、KLabのゲーム開発・運用の中で培われた様々な技術や挑戦とそのノウハウについて、広く紹介していきます。2017/07/06EmscriptenからSSEとかpthreadを使って爆速にするWebでとにかく高速に計算したいやまだです。Webでとにかく高速な計算を行うために人生の何%かを使っています。前回はJavaScriptから直接SIMD.jsを呼びましたが今回はEmscriptenを使用し、C言語からSIMD命令を呼び出してみます。題材としては定番ですがマンデルブロ集合を使用します。マンデルブロ集合は以下の漸化式で計算が可能でしばしば並列演算の課題としてとりあげられます。複素数なので実部と虚部をXY平面に表すと以下のようになります。Emscriptenを使う今回はWebでということでC言語のコードをJavaScriptコードにコンパイルするEmscriptenを使用します。Emscriptenを使用するとasm.jsを利用した最適化をかけることができるため単純にJavaScriptで実装した時よりも高速になることがあります。以降を指定するとasm.jsが有効となります。使用して計測しました。Emscriptenでコンパイルすることを前提としてCでマンデルブロ集合を実装すると以下のようになります。}}全ピクセルに対してN回ループする必要があるため非常に重い処理であることがひと目でわかります。実行時間はマンデルブロ集合のループ計算を開始してからテクスチャ用のRGBバッファに変換するまでの時間を計測しています。3414msスレッドを使うcompute関数の内側のループはスレッドを使用して分割できそうですのでこちらに挑戦してみます。Emscriptenはマルチスレッドライブラリであるpthreadを実験的にサポートしています。USE_PTHREADS=1を加えることによりpthreadを有効にできます。Nightlyでのみ動作します。}}結果は以下のようになりました。単一スレッドで実行した時に比べて1.7倍程度高速化できています。計測環境はCPUコア数が2であったこともあり、4スレッドにしたとしてもパフォーマンス向上は体感できませんでした。コア数がもっと多いCPUですと演算器の数の制限などはあるでしょうが、スレッド数を増やすことによりパフォーマンスが向上することが期待できます。1952msSIMDを使うさて、もう一つの高速化の方法として1命令で複数の計算処理が可能なSIMD命令を使用してみます。SIMD命令に対応しているブラウザでのみ動作します。SIMDを使用するにはいくつか方法があります。LLVMの自動ベクトル化機能を使用するGCC/Clang固有のSIMD拡張を使用するIntelのSIMD拡張であるSSEを使用する今回はSSEを使用します。SSSE3のみ対応しています。SSEを使用するにはコンパイル時に-msseオプションを指定します。SSEを使用する場合は128ビット幅の__m128を使用します。__m128には32ビットfloatが4つパックされています。_mm_add_psや_mm_mul_psがSSE用の関数ですので演算にはこちらを使用します。見ての通り_mm_add_psが加算、_mm_mul_psが乗算APIとなります。公式リファレンスにアラインメントの指定なども書かれているので、こちらの指示に従った形でメモリ確保をする必要があります。SSEは16ビットにアラインされたバッファが必要となるため、専用のaligned_allocでメモリを確保します。aligned_allocはEmscriptenでビルドすると関数が見つからずにエラーとなってしまったため、Emscriptenのbenchmark_sseで使用されているマクロを使用することにしました。}}実行結果は以下の通り3414msから1659msに約2倍程度高速化しています。理想を言えば4倍程度になって欲しいのですが複素数をRGBに変換する処理などいくらかオーバーヘッドが発生しています。1659msSSEとpthreadの併用さて、ではSSEとpthreadは同時に使えないものかと思い併用してみました。ソースコードは省略しますがあっさりうまくいってしまい、3倍程度の高速化に成功しました。Chromeは残念ながらSSEもpthreadも対応していません。Nightlyよりも良好なパフォーマンスを得ることができました。JavaScript実行エンジンの違いでの差ということになります。2065msWebAssembly本当はWebAssemblyでコンパイルしたかったのですが、以下のようなエラーがでていました。pthreadsまだ、pthreadは対応していないようです。まとめ処理時間をまとめてみました。効果的に高速化されています。今後はSSEやpthreadを使った高速化に積極的に挑戦していきたいです。Buildということもあり結果が安定していない印象を受けました。ここまでSIMD推しできましたが直近ちょっとした事件が発生しました。Proposalに移動しました。今後はWebAssemblyの一部としてSIMDの実装は続けられていくようです。マルチスレッドやSIMDは従来はWebになかったチューニング手段です。ゲームを始めとしてWebがプラットフォームとして育っていくのを見るとわくわくしますね。