We Love SIMD !!
About This Contents
JavaScriptのSIMD APIと逐次処理の性能比較。
SIMD APIは開発者向けのAPIです。対応ブラウザはこちら(Firefox Nightly)
Coding
SIMD APIによる並列処理の注意点
- 128bit浮動小数点レジスタを使用
- SIMDオブジェクト(浮動小数点レジスタ用の変数)には通常の四則演算は利用不可
- SIMDオブジェクトと通常の変数との間ではLoadやStore命令のみでデータをコピー
以下、内積のサンプルコード
▼ main.js
- function dot_simd(n,a,b) {
- var ans = 0.0; //最終的な答えを記録する変数
- var vecA = new Float32Array(a); //配列a,bを単精度配列へ型変換
- var vecB = new Float32Array(b);
- var vecR = new Float32Array(4);
- var xmm0 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //浮動小数点レジスタ[128bit]の準備
- var xmm1 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //単精度データ[32bit]を4つ格納可能
- var xmm2 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //すべて0で初期化
- var xmm3 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); // ※C言語の_mm_set_ps(0,0,0,0)に該当
-
- //演算部分(単精度データに対して、1命令4同時演算)
- for( var i=0; i<(n-3)|0; i=(i+4)|0 ) //1命令4同時演算のため、ループは4ずつ増える
- xmm1 = SIMD.Float32x4.load(vecA, i); //配列a[i]から単精度データ4つをレジスタxmm1に読み込み
- xmm2 = SIMD.Float32x4.load(vecB, i); //配列b[i]から単精度データ4つをレジスタxmm2に読み込み
- xmm3 = SIMD.Float32x4.mul(xmm1, xmm2); //xmm1とxmm2の乗算結果をレジスタxmm3に保存
- xmm0 = SIMD.Float32x4.add(xmm0, xmm3); //乗算結果xmm3をレジスタxmm0に足し込み
- }
- SIMD.Float32x4.store(vecR,0,xmm0); //水平加算用配列vecR[0]からvecR[3]の範囲にxmm0を書き出し
- for( ; i<(n)|0; i=(i+1)|0 ) {
- ans = ans + vecA[i] * vecB[i]; //内積のベクトル長が4の倍数でないときに端数を処理
- }
- ans = ans + vecR[0] + vecR[1] + vecR[2] + vecR[3]; //水平加算
- return (ans);
- }
Calculation of Dot()
SIMD APIで内積を実装し、速度および性能を比較。[Exec]から実行。
JavaScriptのSIMDではSSE2までの対応のため、単精度データに対して1命令4同時演算が可能である。
SIMD | not SIMD | ||||
---|---|---|---|---|---|
配列長 | 時間 [s] | 性能 [GFLOPS] | 時間 [s] | 性能 [GFLOPS] | SIMD/not SIMD |