Boost.SIMD

  • 10,942 views
Uploaded on

BoostCon 2011でのJoel Falcou, Mathias Gaunardによる発表「Practical SIMD acceleration with Boost.SIMD」の日本語訳。

BoostCon 2011でのJoel Falcou, Mathias Gaunardによる発表「Practical SIMD acceleration with Boost.SIMD」の日本語訳。

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • Takahashiさん
    ご回答ありがとうございます。
    Nt2ライブラリをつかってみて感触をたしかめてみます。
    わくわくしながらまつとします。
    Are you sure you want to
    Your message goes here
  • 1touh2 さん
    このライブラリは元々NT2という名前で開発されていたライブラリですので、そちらからダウンロードできます。
    http://nt2.sourceforge.net/start.html

    Boostに移植されるコードは、GSoCのときに以下の場所にコミットされる予定です。
    https://github.com/Mathieu-/boost-simd
    Are you sure you want to
    Your message goes here
  • 翻訳ありがとうございます。
    実際これはどこでダウンロードできるのでしょうか?
    Are you sure you want to
    Your message goes here
  • 翻訳元データ:
    https://github.com/boostcon/2011_presentations/raw/master/thu/simd.pdf
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
10,942
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
47
Comments
4
Likes
5

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Boost.SIMDによる実用的な SIMDアクセラレーションMathias Gaunard Joël Falcou Jean-Thierry Lapresté MetaScale Boostcon 2011 翻訳 : 高橋 晶(faithandbrave@gmail.com)
  • 2. コンテキストコンテキストNT2からBoost.SIMDへ • 昨年、我々はハイパフォーマンスな数値計算のための、Matlabライクな ProtoベースのライブラリであるNT2のプレゼンテーションを行った • Boost.SIMDは、SIMDサブコンポーネント抽出のライブラリ • GSoCプロジェクトが、レビュー準備のために今年の夏に行われる予定 • ここでは、どんな提案をするのかについて話す
  • 3. SIMDSIMDとは何か? 原則 • ひとつの命令、複数 のレジスタ • ひとつのレジスタの NxT要素に適用された 操作 • 通常のALU/FPUよりN 倍速い
  • 4. SIMDの抽象化SIMDの抽象化はなぜ必要なのか?x86ファミリー• MMX 64-bit float, double PowerPCファミリー• SSE 128-bit float • AltiVec 128-bit int8, int16,• SSE2 128-bit int8, int16, int32, int64, float• int32, int64, double • Cell SPU 128-bit int8, int16,• SSE3 int32, int64, float, double• SSSE3• SSE4a (AMD only)• SSE4.1 ARMファミリー• SSE4.2• AVX 256-bit float, double • VFP 64-bit float, double• FMA4 (AMD only) • NEON 64-bit and 128-bit• XOP (AMD only) float, int8, int16, int32, int64• FMA3
  • 5. 明示的なSIMD並列化コンパイラはなぜそれをしないのか?コンパイラはとても賢いだけ • 自動ベクトル化(auto vectorization)は以下のような場合にだけ起こるこ とができる: – (何者かの代わりに)メモリを扱う者が決まっている – コードは本来ベクトル化が可能である • コンパイルされた関数はベクトル化されない(libmなど) • コンパイラには、それが何をベクトル化することができるか判 断できるくらいの静的な情報がいつでもあるわけではない • ベクトル化のための設計は、ヒューマンプロセスである結論 • 明確にSIMD並列性を宣言するのは、あなたのコードをベクトル化させる最 も良い方法である • このプレゼンテーションでデモンストレーションを行う
  • 6. Talk Layout1. はじめに2. インタフェース3. SIMDとSTL4. SIMD仕様イディオム5. 結論
  • 7. SIMD手書き手書きしてみる 32ビット整数のベクトルでa * b + cする : SSE __m128i a, b, c, result ; result = _mm_mul_epi32 (a, _mm_add_epi32 (b, c)); 32ビット整数のベクトルでa * b + cする : Altivec __vector int a, b, c, result ; result = vec_cts ( vec_madd ( vec_ctf (a ,0) , vec_ctf (b ,0) , vec_ctf (c ,0) ) ,0);
  • 8. パックパック抽象化simd::pack<T> pack<T, N> 型TのN要素をパックするSIMDレジスタ pack<T> 利用可能な最適なNを自動的に使用する • TとT以外のパックという例外操作を除いて、それはTのように振舞う。制約 • Tは基本的な算術型でなければならない。たとえば:(un)signed char, (unsigned) short, (unsigned) int, (unsigned) long, (unsigned) long long, float or double - not bool. • Nは2のべき乗でなければならない
  • 9. プリミティブパック抽象化 演算子 • オーバーロード可能な全ての演算子が利用できる • pack<T> × pack<T>操作だけでなくpack<T> × Tも可能 • 型の強制と昇格の無効 uint8_t(255) + uint8_t(1)はint(256)ではなくuint_t(0)となる 比較 • ==, !=, <, <=, >=は、語彙比較(lexical comparison)を行う • eq, neq, lt, gt, le, ge関数は、boolのpackを返す その他のプロパティ • ReadOnlyRandomAccessFusionSequenceとReadOnlyRandomAccessRange の両方をモデル化する • at_c<i>(p)もしくはp[i]をアクセスに使用できる。i番目の要素へのアクセス は便利だが遅い(at_cは速い)
  • 10. プリミティブpack API メモリアクセス pack<T, N>からT*、もしくはその逆にload/storeを行うには、メモリはsizeof(T)*N にアライメントされていなければならない。エラー時の振る舞いは未定義 Examples
  • 11. プリミティブpack API メモリアクセス pack<T, N>からT*、もしくはその逆にload/storeを行うには、メモリはsizeof(T)*N にアライメントされていなければならない。エラー時の振る舞いは未定義 例 load< pack<T, N> >(p, i)はp + i*Nアライメントされたアドレスからloadされる
  • 12. プリミティブpack API メモリアクセス pack<T, N>からT*、もしくはその逆にload/storeを行うには、メモリはsizeof(T)*N にアライメントされていなければならない。エラー時の振る舞いは未定義 例 load< pack<T, N>, Offset>(p, i)はp + i*N + Offsetアライメントされたアドレスから loadされる 。p + iはアライメントされていなければならない。
  • 13. プリミティブpack API メモリアクセス pack<T, N>からT*、もしくはその逆にload/storeを行うには、メモリはsizeof(T)*N にアライメントされていなければならない。エラー時の振る舞いは未定義 例 store(p, i, pk)はp + i*Nアライメントされたアドレスでpkにstoreする
  • 14. プリミティブproto entityとしてのpack 論拠 • ほとんどのSIMD ISAはfused操作を持っている(FMA, etc...) • 簡単なコードを書いて最も良いパフォーマンスを得たい • 遅延評価が必要 : protoに助けてもらおう! 利点 • 全ての式や関数が、変換演算子で評価されるテンプレート式を生成する • a * b + cはfma(a, b, c)にマッピングされる a + b * cはfma(b, c, a)にマッピングされる !(a < b)はis_nle(a, b)にマッピングされる • 拡張のための最適化システムは開かれている
  • 15. プリミティブ他の算術、ビット、ieee演算と述語 算術演算 ビット演算 述語 • saturated • select • ゼロとの比較 arithmetic • andnoot, ornot • 比較の否定 • float/int変換 • popcnt • is_unord, is_nan, • round, floor, ceil, • ffs is_invalid trunk • ror, rol • is_odd, is_even, • sqrt, hypot • rshr, rshl • majority • average • twopower • random • min/max IEEE • rounded division and • ilogb, frexp remainder • ldexp • next/prev • ulpldist
  • 16. プリミティブReductionとSWAR演算 Reduction SWAR • any, all • group / split • nbtree • slatetd reduction • minimum/maximum, • cumsum posmin/posmax • sort • sum • product, dot product
  • 17. 拡張ポイントnative<T, X> : archのTに関するSIMDレジスタ。X セマンティクス • packと似ているが、全ての演算と関数の戻り値がExpression Templateを 返すわけではない。 • Xは命令ではなく使用可能な型の登録。SSEの全てのバリエーションのタグ だけを指定する。 • ライブラリを拡張するために使用されなければならないのはインタフェース である。 例 native<float, tag::sse_> は __m128 をラップする native<uint8_t, tag::sse_> は __m128i をラップする native<double, tag::avx_> は __m256d をラップする native<double, tag::altivec_> は __vector float をラップする
  • 18. 拡張ポイントnative<T, X> : archのTに関するSIMDレジスタ。X ソフトウェアフォールバック • tag::none_<N>は、Nバイトサイズのレジスタによる、ソフトウェアエミュレー トされたSIMDアーキテクチャ • 満足のいくSIMDアーキテクチャが見つからない場合にフォールバックとし て使用する • これのおかげで、コードのデグレードが汎用的なまま • SIMDが見つからない場合のデフォルトのネイティブ型 : native<T, tag::none_<8> >
  • 19. RGBをグレースケールにするRGBをグレースケールにするスカラバージョン float const *red, *green, *blue; float* result; for (std::size_t i = 0; i != height * width ; ++i) result[i] = 0.3f * red[i] + 0.59f * green[i] + 0.11f * blue[i];SIMDバージョン std::size_t N = meta::cardinal_of<pack<float> >::value; for (std::size_t i = 0; i != height*width/N; ++i) { pack<float> r = load< pack<float> >(red, i); pack<float> g = load< pack<float> >(green, i); pack<float> b = load< pack<float> >(blue, i); pack<float> res = 0.3f * r + 0.59f * g + 0.11f * b; store(res, result, i); }
  • 20. プリミティブ簡単だが、どうすれば… • …RGB or RGBAが混在していたらどうするか? • …floatではなく8ビット整数だったら? 複雑に聞こえるものは、あとで紹介する。
  • 21. Talk Layout1. はじめに2. インタフェース3. SIMDとSTL4. SIMD仕様イディオム5. 結論
  • 22. 論拠演算 vs データ どこで/どのようにデータを格納するか • SIMD演算はデータ上で動作する必要がある • 通常のアプローチでは、ユーザーに規定されたコンテナを強制する • これは十分にジェネリックではない より良いアプローチ • SIMD準拠アロケータ • SIMDのRangeとイテレータ : CountiguousRange • 標準アルゴリズムのサブセットを操作するためにSIMDクラスをアダプトする
  • 23. 論拠演算 vs データ どこで/どのようにデータを格納するか • SIMD演算はデータ上で動作する必要がある • 通常のアプローチでは、ユーザーに規定されたコンテナを強制する • これは十分にジェネリックではない より良いアプローチ • SIMD準拠アロケータ • SIMDのRangeとイテレータ : CountiguousRange • 標準アルゴリズムのサブセットを操作するためにSIMDクラスをアダプトする
  • 24. SIMDアロケータSIMDアロケータ 論拠 • SIMDに準拠した方法でメモリを処理するコンテナを許可する • メモリのアライメントをハンドル • メモリのパディングをハンドル例 std::vector<float, simd::allocator<float> > v(173); assert( simd::is_aligned(&v[0]) );
  • 25. SIMDイテレータとRangeRangeからSIMD Rangeへ イテレータインタフェース • Boost.SIMDは、simd::begin()/simd::end()を提供する • SIMDイテレータはpackを返して回るイテレータ • regular rangeをとり、SIMD上でイテレートする Examples
  • 26. SIMDイテレータとRangeRangeからSIMD Rangeへ イテレータインタフェース • Boost.SIMDは、simd::begin()/simd::end()を提供する • SIMDイテレータはpackを返して回るイテレータ • regular rangeをとり、SIMD上でイテレートする 例
  • 27. SIMDイテレータとRangeRangeからSIMD Rangeへ イテレータインタフェース • Boost.SIMDは、simd::begin()/simd::end()を提供する • SIMDイテレータはpackを返して回るイテレータ • regular rangeをとり、SIMD上でイテレートする 例 std::vector<float, simd::allocator<float> > v(1024); pack<float> x,z; x = std::accumulate( simd::begin(v.begin()) , simd::end(v.end()) , z );
  • 28. SIMDイテレータとRangeRangeからSIMD Rangeへ イテレータインタフェース • Boost.SIMDは、simd::begin()/simd::end()を提供する • SIMDイテレータはpackを返して回るイテレータ • regular rangeをとり、SIMD上でイテレートする 例 std::vector<float, simd::allocator<float> > v(1024); pack<float> x,z; x = boost::accumulate( simd::range(v), z );
  • 29. SIMDイテレータとRangeRangeからSIMD Rangeへ イテレータインタフェース • nativeとpackは、begin()/end()を提供する • 標準アルゴリズムを直接使用可能 • Boost.Rangeアルゴリズムを直接使用可能 例 pack<float> x(1, 2, 3, 4); float k = std::accumulate(x.begin() x.end(), 0.f );
  • 30. SIMDイテレータとRangeRangeとしてのSIMD値 全てをまとめる std::vector<float, simd::allocator<float> > v(1024); pack<float> x, z; float r; x = boost::accumulate(simd::range(v), z); r = std::accumulate(x.begin(), x.end(), 0.f);
  • 31. SIMDイテレータとRangeRangeとしてのSIMD値 全てをまとめる – より良いバージョン std::vector<float, simd::allocator<float> > v(1024); float r; r = sum(accumulate(simd::range(v), pack<float>()));
  • 32. SIMDイテレータとRangeRangeとしてのSIMD値 doubleでのstd::accumulateの高速化
  • 33. SIMDイテレータとRangeRangeとしてのSIMD値 floatでのstd::accumulateの高速化
  • 34. SIMDイテレータとRangeSIMD RangeとジェネリックなSIMD/スカラーコード RGB2Greyに戻る template <class RangeIn, class RangeOut> inline void rgb2grey( RangeOut result, RangeIn red, RangeIn green, RangeIn blue ) { typedef typename RangeIn::iterator in_iterator; typedef typename RangeOut::iterator iterator; typedef typename iterator_value< iterator >::type type; iterator br = result.begin(), er = result.end(); in_iterator r = red.begin(); in_iterator g = green.begin(); in_iterator b = blue.begin(); while ( br != er ) { type rv = load< type >(r, 0); type gv = load< type >(g, 0); type bv = load< type >(b, 0); type res = 0.3f * rv + 0.59f * gv + 0.11f * bv; store(res, br, 0); br++; r++; g++; b++; } }
  • 35. SIMDイテレータとRange何が足りないか 統合されたSIMDサポート • ほとんどの標準アルゴリズムが、一息で実行できるように特殊化されるべ きだ • simd(r)のようなRangeアダプタができるだろうか? • load<T, N>を使用したshifted Rangeのサポート いくつかのSIMDによる頭の体操 • SIMD find? • SIMD sort? • copyのような高速化?
  • 36. Talk Layout1. はじめに2. インタフェース3. SIMDとSTL4. SIMD仕様イディオム5. 結論
  • 37. 条件ハンドリングSIMDでの真理値問題 pack<float> x(1 ,2 ,3 ,4); pack<float> c(2.5); cout << lt(x,c) << endl;
  • 38. 条件ハンドリングSIMDでの真理値問題 pack<float> x(1 ,2 ,3 ,4); pack<float> c(2.5); cout << lt(x,c) << endl; (( Nan Nan 0 0 ))
  • 39. 条件ハンドリングSIMDでの真理値問題 pack<float> x(1 ,2 ,3 ,4); pack<float> c(2.5); cout << lt(x,c) << endl; (( Nan Nan 0 0 ))解決策 Tに適切なtrue値w/rを返すTrue<T>() Tに適切なfalse値w/rを返すFalse<T>()
  • 40. 条件ハンドリングSIMDでの条件式例 // スカラーコード if( x > 4 ) y = 2*x; else z = 1.f/x; // SIMD code // ???
  • 41. 条件ハンドリングSIMDでの条件式例 // スカラーコード if( x > 4 ) y = 2*x; else z = 1.f/x; // SIMD code y = where( gt(x, 4), 2*x, y); z = where( gt(x, 4), z, 1.f/x);
  • 42. シフトした読み込み動機
  • 43. シフトした読み込み着々と進んでいる…
  • 44. シフトした読み込みベクトルの解決策
  • 45. シフトした読み込みベクトルの解決策SIMD/スカラーバージョン template < class RangeIn, class RangeOut > inline void average( RangeOut result, RangeIn input ) { typedef typename RangeIn::iterator in_iterator; typedef typename RangeOut::iterator iterator; typedef typename iterator_value< iterator >::type type; iterator br = result.begin(), er = result.end(); in_iterator data = input.begin(); br++; er--; while ( br != er ) { type xm1 = load<type, -1>(data, i); type x = load<type>(data, i); type xp1 = load<type, +1>(data, i); store(res, i, 0) = 1.f/3 * (xm1 + x + xp1); } }
  • 46. 昇格と飽和(Promotion and Saturation)RGB2Greyへ戻る 8ビットRGB static const std::size_t N = meta::cardinal_of< pack<uint8_t> >::value; for (std::size_t i = 0; i != height*width/N; ++i) { pack<uint8_t> r = load< pack<uint8_t> >(red, i); pack<uint8_t> g = load< pack<uint8_t> >(green, i); pack<uint8_t> b = load< pack<uint8_t> >(blue, i); pack<uint8_t> res = uint8_t(77) * r / uint8_t(255) + uint8_t(150) * g / uint8_t(255) + uint8_t(28) * b / uint8_t(255); store(res, result, i); }
  • 47. 昇格と飽和(Promotion and Saturation)RGB2Greyへ戻る packの昇格 uint16_t r_coeff = 77; uint16_t g_coeff = 150; uint16_t b_coeff = 28; uint16_t div_coeff = 255; pack<uint16_t> r1, r2, g1, g2, b1, b2; tie(r1, r2) = split(r); tie(g1, g2) = split(g); tie(b1, b2) = split(b); pack<uint16_t> res1 = (r_coeff * r1 + g_coeff * g1 + b_coeff * b1) / div_coeff; pack<uint16_t> res2 = (r_coeff * r2 + g_coeff * g2 + b_coeff * b2) / div_coeff; pack<uint8_t> res = group(res1, res2);
  • 48. Talk Layout1. はじめに2. インタフェース3. SIMDとSTL4. SIMD仕様イディオム5. 結論
  • 49. Boost.SIMDの概要proto entityとしてのpack 我々の目標 • SIMDプログラミングに、使いやすい状態をもたらす • もしboost.atomicがあったら、boost.simdをどうするか? • C++の残りのすばらしいものを使って、さらに魅力的にする 我々が達成したいこと • NT2で学んだことの活用する • パフォーマンス用語のいくつかの影響を実証する • スカラーを使用する場合と同じくらい単純なSIMD命令にする
  • 50. 今後の活動Google Summer of Code 2011• 混乱をクリーンナップし、boostifyにする• STL/Boostとの互換性を向上させる• 募集:このライブラリを実際に活用したアプリケーション
  • 51. Thanks for your attension