一般的に、SSE / MMXに関連して「ネット上で」出くわすものはすべて、ベクトルとマトラシーの数学的なものとして出てきます。ただし、 Agner Fogが提供するような、SSEに最適化された「標準関数」のライブラリ、またはGCCのSSEベースの文字列スキャンアルゴリズムの一部を探しています。
簡単な一般的な要約として:これらは、memset、memcpy、strstr、memcmp BSR / BSF、つまりSSEintrsuctionsから構築されたstdlib風のものになります。
アセンブリではなく組み込み関数を使用するSSE1(正式にはMMX2)用にするのが望ましいですが、どちらでも構いません。うまくいけば、これはあまり広い範囲ではありません。
アップデート1
いくつか検索した後、私はいくつかの有望なものに出くわしました、1つのライブラリが私の目を引きました:
- LibFreeVec:mac / IBMのみのようです(AltiVecベースであるため)、したがって(私には)ほとんど役に立ちません。さらに、直接ダウンロードリンクが見つからないようです。また、サポートされている最小のSSEバージョンも記載されていません。
また、いくつかのベクトル化された文字列関数(strlen、strstr strcmp)に関する記事に出くわしました。ただし、SSE4.2は私の手の届かないところにあります(前に述べたように、SSE1 / MMXに固執したいと思います)。
アップデート2
Paul Rは、少しベンチマークを行うように動機付けました。残念ながら、私のSSEアセンブリコーディングの経験はzipに近いため、他の誰か(http://www.mindcontrol.org/~hplus/)のベンチマークコードを使用して追加しました。完全/カスタマイズされた最適化を使用してVC9SP1でコンパイルされたすべてのテスト(元のVC6 SP5を除く)/arch:SSE
。
最初のテストは、SSE1でキャップされた私のホームマシン(AMD Sempron 2200+ 512mb DDR 333)の1つでした(したがって、MSVC memcpyによるベクトル化はありません):
comparing P-III SIMD copytest (blocksize 4096) to memcpy
calculated CPU speed: 1494.0 MHz
size SSE Cycles thru-sse memcpy Cycles thru-memcpy asm Cycles thru-asm
1 kB 2879 506.75 MB/s 4132 353.08 MB/s 2655 549.51 MB/s
2 kB 4877 598.29 MB/s 7041 414.41 MB/s 5179 563.41 MB/s
4 kB 8890 656.44 MB/s 13123 444.70 MB/s 9832 593.55 MB/s
8 kB 17413 670.28 MB/s 25128 464.48 MB/s 19403 601.53 MB/s
16 kB 34569 675.26 MB/s 48227 484.02 MB/s 38303 609.43 MB/s
32 kB 68992 676.69 MB/s 95582 488.44 MB/s 75969 614.54 MB/s
64 kB 138637 673.50 MB/s 195012 478.80 MB/s 151716 615.44 MB/s
128 kB 277678 672.52 MB/s 400484 466.30 MB/s 304670 612.94 MB/s
256 kB 565227 660.78 MB/s 906572 411.98 MB/s 618394 603.97 MB/s
512 kB 1142478 653.82 MB/s 1936657 385.70 MB/s 1380146 541.23 MB/s
1024 kB 2268244 658.64 MB/s 3989323 374.49 MB/s 2917758 512.02 MB/s
2048 kB 4556890 655.69 MB/s 8299992 359.99 MB/s 6166871 484.51 MB/s
4096 kB 9307132 642.07 MB/s 16873183 354.16 MB/s 12531689 476.86 MB/s
2番目のテストバッチは、大学のワークステーション(Intel E6550、2.33Ghz、2gb DDR2 800?)で実行されました。
VC9 SSE/memcpy/ASM:
comparing P-III SIMD copytest (blocksize 4096) to memcpy
calculated CPU speed: 2327.2 MHz
size SSE Cycles thru-sse memcpy Cycles thru-memcpy asm Cycles thru-asm
1 kB 392 5797.69 MB/s 434 5236.63 MB/s 420 5411.18 MB/s
2 kB 882 5153.51 MB/s 707 6429.13 MB/s 714 6366.10 MB/s
4 kB 2044 4447.55 MB/s 1218 7463.70 MB/s 1218 7463.70 MB/s
8 kB 3941 4613.44 MB/s 2170 8378.60 MB/s 2303 7894.73 MB/s
16 kB 7791 4667.33 MB/s 4130 8804.63 MB/s 4410 8245.61 MB/s
32 kB 15470 4701.12 MB/s 7959 9137.61 MB/s 8708 8351.66 MB/s
64 kB 30716 4735.40 MB/s 15638 9301.22 MB/s 17458 8331.57 MB/s
128 kB 61019 4767.45 MB/s 31136 9343.05 MB/s 35259 8250.52 MB/s
256 kB 122164 4762.53 MB/s 62307 9337.80 MB/s 72688 8004.21 MB/s
512 kB 246302 4724.36 MB/s 129577 8980.15 MB/s 142709 8153.80 MB/s
1024 kB 502572 4630.66 MB/s 332941 6989.95 MB/s 290528 8010.38 MB/s
2048 kB 1105076 4211.91 MB/s 1384908 3360.86 MB/s 662172 7029.11 MB/s
4096 kB 2815589 3306.22 MB/s 4342289 2143.79 MB/s 2172961 4284.00 MB/s
ご覧のとおり、SSEは私のホームシステムでは非常に高速ですが、Intelマシンでは機能しません(おそらくコーディングが不適切なためですか?)。私のx86アセンブリバリアントは、自宅のマシンで2番目、Intelシステムで2番目になります(ただし、結果は少し一貫性がないように見えます。1つの抱擁がSSE1バージョンを支配します)。MSVC memcpyは、手作業で行われたIntelシステムテストに勝ちます。これはSSE2のベクトル化によるものですが、私の自宅のマシンでは、ひどいものでさえも__movsd
それを打ち負かします...
落とし穴:メモリはすべて2の累乗で調整されていました。キャッシュは(うまくいけば)フラッシュされました。タイミングにはrdtscを使用しました。
興味深い点:MSVCには(どの参照にもリストされていない)__movsd組み込み関数があり、使用しているのと同じアセンブリコードを出力しますが、(インライン化されている場合でも)陰気に失敗します。それがおそらくその非公開の理由です。
VC9 memcpyは、sse 2以外のマシンで強制的にベクトル化することができますが、FPUスタックが破損しますが、バグもあるようです。
これは、私がテストに使用したものの完全なソースです(これも、オリジナルのhttp://www.mindcontrol.org/~hplus/へのクレジットを含みます)。プロジェクトファイルのバイナリは、リクエストに応じて利用できます。
結論として、MSVC crtのものと同様に、スイッチングバリアントが最適であるように思われますが、より多くのオプションと単一の1回限りのチェック(インライン関数ポインターを介して?または内部直接呼び出しのようなより悪質なものを介して)ではるかに頑丈ですパッチ)、ただし、インライン化はおそらく代わりに最良の方法を使用する必要があります
アップデート3
Eshanが尋ねた質問は、これに関連する有用なものを思い出させました。ビットセットとビット演算、BitMagicのみで、大きなビットセットに非常に役立ちますが、 SSE2(ビット)最適化に関するすばらしい記事もあります。残念ながら、これはまだCRT/stdlib風のタイプライブラリではありません。これらのプロジェクトのほとんどは、(問題の)特定の小さなセクションに専念しているようです。
これは疑問を投げかけます。オープンソースの、おそらくマルチプラットフォームのパフォーマンスcrt / stdlibプロジェクトを作成し、それぞれが特定の状況に最適化されたさまざまなバージョンの標準化された関数と「ベストケース」を作成することは価値がありますか? '/関数の汎用バリアント。スカラー/MMX/ SSE / SSE2 +(MSVC)のランタイム分岐または強制コンパイル時のスカラー/SIMDスイッチのいずれかを使用します。
これは、HPC、またはパフォーマンスのすべてのビットが重要なプロジェクト(ゲームなど)に役立つ可能性があり、プログラマーは組み込み関数の速度について心配する必要がなく、最適な最適化されたバリアントを見つけるためにわずかな調整が必要です。
アップデート4
この質問の性質を拡張して、SSE / MMXを使用して非ベクトル/マトリックスアプリケーションの最適化に適用できる手法を含める必要があると思います。これは、おそらく32/64ビットスカラーコードにも使用できます。良い例は、スカラー技術(ビット操作)、MMXおよびSSE / SIMDを使用して、特定の32/64/128/256ビットデータ型のバイトの発生を一度にチェックする方法です。
また、「ICCを使うだけ」という答えがたくさんありますが、それは良い答えです。まず、ICCは継続的に使用できるものではないため、私のような答えではありません(Intelに無料の学生版がない限り)Windowsの場合)、30回の試行のため。第二に、そしてより適切には、私はライブラリ自体だけでなく、ライブラリに含まれる関数を最適化/作成するために使用される技術を個人的な教育と改善のために使用しているので、そのような技術と原則を自分のコードに適用できます(必要に応じて)、これらのライブラリの使用と組み合わせて。うまくいけば、それはその部分をクリアします:)