SSK's Memo


We Love SIMD !!

About This Contents

JavaScriptのSIMD APIと逐次処理の性能比較。

SIMD APIは開発者向けのAPIです。対応ブラウザはこちら(Firefox Nightly)

Coding

SIMD APIによる並列処理の注意点

  • 128bit浮動小数点レジスタを使用
  • SIMDオブジェクト(浮動小数点レジスタ用の変数)には通常の四則演算は利用不可
  • SIMDオブジェクトと通常の変数との間ではLoadやStore命令のみでデータをコピー

以下、内積のサンプルコード

▼ main.js

  1. function dot_simd(n,a,b) {
  2. var ans = 0.0; //最終的な答えを記録する変数
  3. var vecA = new Float32Array(a); //配列a,bを単精度配列へ型変換
  4. var vecB = new Float32Array(b);
  5. var vecR = new Float32Array(4);
  6. var xmm0 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //浮動小数点レジスタ[128bit]の準備
  7. var xmm1 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //単精度データ[32bit]を4つ格納可能
  8. var xmm2 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); //すべて0で初期化
  9. var xmm3 = SIMD.Float32x4(0.0, 0.0, 0.0, 0.0); // ※C言語の_mm_set_ps(0,0,0,0)に該当
  10.  
  11. //演算部分(単精度データに対して、1命令4同時演算)
  12. for( var i=0; i<(n-3)|0; i=(i+4)|0 ) //1命令4同時演算のため、ループは4ずつ増える
  13. xmm1 = SIMD.Float32x4.load(vecA, i); //配列a[i]から単精度データ4つをレジスタxmm1に読み込み
  14. xmm2 = SIMD.Float32x4.load(vecB, i); //配列b[i]から単精度データ4つをレジスタxmm2に読み込み
  15. xmm3 = SIMD.Float32x4.mul(xmm1, xmm2); //xmm1とxmm2の乗算結果をレジスタxmm3に保存
  16. xmm0 = SIMD.Float32x4.add(xmm0, xmm3); //乗算結果xmm3をレジスタxmm0に足し込み
  17. }
  18. SIMD.Float32x4.store(vecR,0,xmm0); //水平加算用配列vecR[0]からvecR[3]の範囲にxmm0を書き出し
  19. for( ; i<(n)|0; i=(i+1)|0 ) {
  20. ans = ans + vecA[i] * vecB[i]; //内積のベクトル長が4の倍数でないときに端数を処理
  21. }
  22. ans = ans + vecR[0] + vecR[1] + vecR[2] + vecR[3]; //水平加算
  23. return (ans);
  24. }

Calculation of Dot()

SIMD APIで内積を実装し、速度および性能を比較。[Exec]から実行。

JavaScriptのSIMDではSSE2までの対応のため、単精度データに対して1命令4同時演算が可能である。

SIMDnot SIMD
配列長時間 [s]性能 [GFLOPS]時間 [s]性能 [GFLOPS]SIMD/not SIMD