SIMD.js を使ってみる
第0回 東京 Web PerformanceでSIMD.jsという勉強会が開催され、SIMD.js を触ってみました。
イベントの内容は @edvakfさんのレポートを見ていただくといいです。
簡単に SIMD.js の効能をいうなら、ループ回数を 1/4 にすることができる仕組み、という感じでしょうか。
- SIMD.js は Firefox Nightly、Chromium SIMD ビルド、Microsoft Edge (要フラグ設定)など、既に Safari を除く主要ブラウザーで実装が存在します。
SIMD.float32x4()
などの、オブジェクトを作る関数は、コンストラクターではないため、new
は付けずに使いますadd
やmul
などのオペレーションは、引数にした SIMD オブジェクトに対して非破壊でおこなわれ、戻り値には新たに SIMD オブジェクトが返されます。- 要素を取得するためには、
SIMD.%type%.extractLane( instance, index )
を使います。index
は0
から始まる整数です - SIMD のオブジェクトは InlineTransparentTypedObject なので、WebWorker と組み合わせて、別のスレッドでも同時進行すると並列処理の恩恵は更に大きくなりそうです。
簡単な例
1 | var a = SIMD.Float32x4( 1.0, 1.0, 1.0, 1.0 ); |
「せっかくベクター的なオブジェクトを扱えるになったのに、マトリクスを書けることができないね」という会話がありました。これは以下のように、ベクターを横ではなく、縦で考えてみると SIMD の長所を活かせそうです。
つまり、ベクターを
1 | var v0 = SIMD.Float32x4( x, y, z, w ); |
のように素直に考えるのではなく、
1 | var x4 = SIMD.Float32x4( x0, x1, x2, x3 ); |
のように、成分ごとに考え、これに対してまとめて操作をすれば、SIMD の特長である並列処理の恩恵をうけることができます。
4 つのベクター 3 にマトリクスを掛ける例を試しに作ってみました (要 SIMD.js をサポートしているブラウザー)
結果として、4 組のベクターに対して、マトリクスを掛けることができました。
1 | var v1 = new Vec3( 1, 1, 1 ); |
また、SIMD.js の本家がマンデルブローをデモに使っていたので、SIMD.js を使ってジュリア集合を描いてみました。パフォーマンスは測っていませんがおそらく、素の JS よりは速いのでしょう。
WebGL で何千、何万という attribute をまとめて処理していることを考えると SIMD はかなり貧弱に見えてしまいます。とはいえ、CPU で並列操作ができるのは、今までのなかった機能なのでとても新鮮に感じました。
4 つごとに細切れの処理で冗長なコードになってしまいそうですが、ライブラリーを作って利用することを前提に覚えておくといいかもしれませんね。だって時代は低レベル API で未来を切り開くエクステンシブル Web なんだから!