1 :
デフォルトの名無しさん :
2010/05/26(水) 14:24:25
MMXはぶってんじゃねーよ
3D NOW!はぶって よし
即死しないといいね。
5 :
1 :2010/05/28(金) 01:09:31
なんか書きこめよ、
6 :
1 :2010/05/28(金) 02:52:41
おい、さっさと俺様に役に立つこと書き込めよ
7 :
1 :2010/05/28(金) 17:06:51
早く書けよ バカ
>>7 即死しなくなるのは 20 くらいだっけ?
君の心意気は買うが、即死しなくなるまで一日一度でよい。
9 :
1 :2010/05/28(金) 17:36:26
>>8 うぜーよてめぇよぉ
誰にけんかうってんだ?
てゆーかさぁ同一人物の書き込みじゃないんだけど?
んなことより、さっさと何か俺の役に立つことを書き込みやがれ
10 :
1 :2010/05/28(金) 18:15:51
即死を避けたいのはわかるが、罵倒はさすがにいかがなものか。 それっぽいコードを貼る、といった程度で勘弁してもらいたい。
>>9 それはいいんだが、翌日になってから投稿すると、効率よく即死回避できるし、
もしかすると無駄な即死回避投稿する前に誰か何かネタを振ってくれるかも知れない。
だから投稿する前に一日待て。
13 :
デフォルトの名無しさん :2010/05/30(日) 01:30:49
AVX使ってみた奴いる? ど〜だった?使いやすい?
何故?
15 :
1 :2010/06/05(土) 00:13:34
なんか書きこめよ、くずども
なんか
17 :
デフォルトの名無しさん :2010/06/05(土) 21:13:26
>>15 無理だろ
たかが1000レスに6年もかかったんだし
2日に1レスが妥当
19 :
デフォルトの名無しさん :2010/06/12(土) 20:22:54
すすまねえな
インテル(R) Advanced Vector Extensions プログラミング・リファレンス
http://download.intel.com/jp/software/AVE/319433-006JA.pdf p.86
3.2 YMM ステート管理
> AVX とFMA拡張をサポートするには、OS がYMM ステートを管理する必要がある。
> そうでない場合には、AVXあるいはFMA 拡張命令(VEX エンコーディングによる
> 拡張128 ビットSIMD 命令を含めて)を実行すると#UD 例外が発生する。
原文
Intel(R) Advanced Vector Extensions Programming Reference
http://software.intel.com/file/21558 P.90
3.2 YMM STATE MANAGEMENT
> An OS must enable its YMM state management to support AVX and FMA extensions.
> Otherwise, an attempt to execute an instruction in AVX or FMA extensions(including
> an enhanced 128-bit SIMD instructions using VEX encoding) will cause a #UD exception.
22 :
デフォルトの名無しさん :2010/06/26(土) 18:26:07
SSEっていつまでサポートされる? 今後SSEのクロックあたりの実行速度が改善される見込みは?
> SSEっていつまでサポートされる? x86/AMD64がサポートされなくなるまで >今後SSEのクロックあたりの実行速度が改善される見込みは? 複数のμOPに分解して実行していた命令が、1μOPで実行 できるような改良はありえる
ビット論理演算て型によらず結果は一緒だよな? なんで型ごとにあるんだ? pxor / xorps / xorps とか。 例外も (対応CPUなら) 同じみたいだし。
>>24 もすこしSIMDを勉強したほうがよく寝?
>>25 どうしてもわからなくて夜も眠れないから
わかるなら教えてくれ!
結果の出し方が違くね?
結果の出し方は同じじゃね?
整数SIMDブロックとFP-SIMDのブロックのそれぞれに用意されている 演算ユニットを明示的に使うため
>>29 何のために?省電力?
パフォーマンスを考えた場合、
xorpd, xorps は PORT5 しか使えず、
pxor はPORT0, PORT1, PORT5 の3つを使える為、
pxor のみで十分だが。
パフォーマンスのためだ 異なるブロック間でのデータのやり取りにはペナルティがあるので 各ブロックに演算ユニットが用意されている
>>24 歴史的経緯に因る。
pdの追加は謎だけど。
ペナルティがあったのって熱湯だけじゃないの?
>>34 chapterごとにページ振ってあるんだが
何章の何ページだ?
へー ポート間じゃなくてintとfpの間に入るんだ
addpd xmm0, xmm1 xorpd xmm0, xmm1 addpd xmm0, xmm1 xorpd xmm0, xmm1 .... と addpd xmm0, xmm1 pxor xmm0, xmm1 addpd xmm0, xmm1 pxor xmm0, xmm1 .... でパフォーマンスを比べてみた。 ●実測 Core2Duo の E8400とT7300では同じタイム。 Corei7 では後者が倍時間がかかった。 ●シミュレーション nehalem / sandy とも同タイム。
addpd xmm0, xmm1 mulpd xmm2, xmm3 pxor xmm4, xmm5 pxor xmm6, xmm7 pxor xmm8, xmm9 の繰り返し のように直後に値を使わない場合は Corei7 だと pxor の方が実測、シミュレーションとも速い。 Core2Duoはこの場合もまったく同じ。
整数演算主体のプロジェクトを /arch:AVXでビルドしてもあまり速くならないの?
SSEとAVX-128bitの組み込み関数は共通なので コンパイラオプションで生成するバイナリを切り替えられる 整数SIMDの組み込み関数を使っているのなら 多少の性能向上はあると思われる
41 :
39 :2010/07/03(土) 12:45:39
エスパーだな。 俺はSSEを使っていないコードかと思った。 それだったら、多分最初の実装だとデコーダをカリカリにチューンはしないだろうから 命令の帯域がクリティカルな人は効果あるんじゃない?としか言えない。 命令長が短くなるのと、三項演算のおかげで退避に使う命令を減らせるからコードが全体的に少しだけ小さくなる。
43 :
39 :2010/07/03(土) 13:50:08
プロジェクトのほんのごく一部にSSE2のintrinsicを使ってます。 さらに/arch:SSEではほとんど速くならず、 /arch:SSE2ではかなり高速化したプロジェクトです。
整数演算入ったのSSE2だし
VCの/archはFPのスカラーコードで使う命令セットを 指定するのが主な使い方なので性能向上に過度な期待は しないほうがいい
46 :
39 :2010/07/03(土) 15:01:42
分かりました。どうもありがとうございました。
>>37-38 スループットの方は単純に fp logic の実行ポート数じゃん (Core2 は3つ、i7 は1つ)
レイテンシの方は、Core2 の fp logic 命令って実は int スタックらしいよ
だからどっち使っても同じ
nehalemでは
>>37 は前者の方が速いので、
ペナルティがあると考えるのが妥当かと。
ただ、シミュレーションの結果と一致しないのは気になるが。
比較対象が違ってるんだが
なにが?
Nehalem の fp logic は fp スタックだから
他の fp 命令と繋ぐのはペナルティなし、int<->fp 繋ぐのは2クロックペナルティ
ってことで
>>34 の資料と一致してるんじゃない
シミュレータは多分うんこ
"シュミレーター" の検索結果 約 334,000 件 (0.14 秒)
>>51 Nehalem のFP/SIMD/SSE2 Move and Logic の Domain は FP と書いてあるんだけど、
これって嘘なの?
54 :
デフォルトの名無しさん :2010/07/17(土) 20:37:01
__m128(fp32x4)の任意の要素に任意の値を書き込みたいんだが、 どういう実装がベストなのかな?↓がベストかな? __m128 set_elem( __m128& v, const uint32_t index, float32_t e ) { ALIGN(16) const float32_t mask_table[4*4] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; const __m128 mask = _mm_load_ps( mask_table + index * 4 ); return _mm_or_ps( _mm_and_ps( _mm_set1_ps(e), mask ), _mm_andnot_ps( v, mask ) ); }
>>54 言語が何か分かんないけど、
float32_t の 1 でマスク作れるの?
andnot って1個目の引数のnotを取ると思うんだけど、順番あってる?
メモリ経由で、直接変更する要素に e を書くのとどっちが早いかなあ。
>>55 すいません、どっちも間違ってましたw
まあ、実際1要素だけ書き換えなんて
やらないんでしょうねえ。
4レジスタくらいなら直接保持したほうが速いと思う で、値は1レジスタにまとめて読み込んで積をとる
画像フォーマットの(en|de)codingで効果を発揮するのはSSE2までだけで十分だったりするの? SSE3 SSSE3 SSE4まで使って頑張ってもSSE2までしか使わない場合と大して変わらないとかあるの?
>>58 だんごさんはSSSE3が画像処理に意外と便利だと言っていたけど
SSSE3 SSE4.1 SSE4.2は無用の長物。
劇的に速くなることはマレだと思うが、 あれば便利な命令は結構ある。 互換性を考えると使いにくいけどね。 一般向け商用ソフトでパフォーマンスが重要なものの場合、 SSE2/SSE3/SSSE3/SSE4.1/SSE4.2/AVX/FMA.... と、すごい種類の可能性があって、 これらすべて用の関数を設計、チューニング、評価なんてとても出来ないから、 SSSE3/SSE4.1/SSE4.2 なんかは飛ばされがち。
OOPのインターフェースつかってSSEのXXを対応したバージョンと、 それ以外のコードの2種類くらいを用意してあげればいいんじゃね? 環境はユーザー責任でスイッチしてもらう。
63 :
デフォルトの名無しさん :2010/07/24(土) 22:04:16
>>62 それやりたいんだけどさ、C++のメンバ関数をアセンブラでどう書けばいいのかがわからない。
インラインアセンブラで書いたプログラムを64ビット用にコンパイルしようとしたら
cl64.exeはインラインアセンブラには対応してないとかエラーが出てコンパイルできないorz
>>63 cl64.exeはインラインアセンブラ非対応。
ml64.exeを使うかintrinsic命令を使うかしかない。
>>62 ユーザーが自分でスイッチは無いな。
普通は実行時に自動判別。
事情により新命令を使ったバージョンしか作らないのなら、
対応してないCPUでの実行時は非対応CPUである旨を表示する。
個人で作った個人用アプリなど、非常に限られた人しか使わないのであれば、
非対応CPUで使ったらいさぎよくOSの例外発生メッセージが出るのもありかも。
>>63 ぶっちゃけそのプログラムは64ビットネイティブにする必要はあるのか?
>>65 おれは最近は、個人でしか使わない趣味のプログラムはすべて64bitネイティブだよ。
レジスタが倍あるし、いまさら窮屈なレジスタ数で組みたくない。
C++オンリーでもパフォーマンスは上だし。
制約が緩くなるのはどう考えても悪いことじゃないな
>>66 そのきもちはすこしわかる。
68系のデータ8本、アドレス8本の環境から、
86系に移ってきたときには窮屈な思いをしたもんだ。
69 :
デフォルトの名無しさん :2010/07/25(日) 19:10:36
>>65 >>63 だが、
>>66 が全部言ってくれた。
インラインアセンブラで組んだウェーブレット変換のプログラムを
ちょっと64ビットで動かしてみたくなったのさ。
CL /FA でアセンブリ出力して、修正、アセンブル、リンクですかのう。
71 :
63 :2010/07/26(月) 00:58:40
>>69 ありがとう
/FAオプションつけてコンパイルしたら、.asmファイルが出てきた
やる気出てきた。
ただ、今はDirectCompute用のプログラム書いてるんだけどね...
一応strategyパターン使ってCPU用とGPU用の処理を分けてる。
72 :
デフォルトの名無しさん :2010/08/08(日) 13:17:01
自作のSSEラップクラスとXMMATRIXの行列積について 生成されるコードを見比べてみたところ(VC2010EE) 自作のは並べ替えが甘くメモリ退避が多く、そのせいか命令数が倍ぐらいで XMMATRIXのに比べて1.5倍ぐらい遅かった。 違いといえばXMMATRIXはイントリンシック命令直書きで 自作のは薄いクラスでラップされているぐらい。畳み込みで 同等のコードが生成されるはずなのに・・ 結局、イントリンシック命令は直書きしないと 最適化がオミットされちゃうんですかね?
>>72 ラップすればするほどパフォーマンスが落ちるのは当たり前だ。
さらに作者の能力や熱意にも大きく依存する。
>>72 メモリのアクセスパターンは重要だよ。命令数が同じでも、キャッシュに乗ってないメモリアクセスが入ると途端に遅くなる。
>>73 適当なことを言うなよ。
>ラップすればするほどパフォーマンスが落ちるのは当たり前だ。
なぜ当たり前と言えるんだ?
別にいくらラップしようが__forceinlineをつけて展開すれば
最後に出来上がるものは同じじゃねーか。
事実、全てインライン展開されているのは確認しているし、
そっから先最適化するかしないかは、コンパイラがやるかやらないかでしかない。
結局、コンパイラが何か俺のわからない理由で最適化を打ち切っているようにしか
みえない。
>さらに作者の能力や熱意にも大きく依存する。
同等のコードが生成されるはず、と書いているように
そもそも同じ様式を採用している。
>>73 一応、ベンチマークなんで、同じ条件で回している。
>>76 結局ちゃちゃいれて終わりか。
なんつーか、無意味な奴。
>>75 確かに、よく分からない理由で
コンパイラが最適化の手をゆるめる事はある
PGOを適用すればレジスタをよりうまく使い回して
メモリアクセスが減るけど
Expressじゃ使えないんだよね
コンパイラの最適化を過信しすぎだな。
>自作のは並べ替えが甘くメモリ退避が多く >一応、ベンチマークなんで、同じ条件で回している 自己矛盾にも気付けないらしい。
>>81 お前バカだろ、もう出てくるなよ。
つーか、何か言いたいことがあるなら
自分が試した結果を交えて話せ。
糞の役にも立たないんだよ。
>>82 悪いけど、コンパイラによる話なんだから該当コンパイラのスレでやってくれ。
空気悪くなって迷惑。
それと、具体的なコードを出さない限り具体的な話なんてできないよ。
SSEと番人は相性悪いな 結局ループせず必要な回数だけ命令を並べるほうが速い 以上チラ裏でした
>>81 自作:メモリ退避が多い
自作じゃない方:メモリ退避が多くないらしい
どう見ても自作の方が不利ですね。ご指摘本当にありがとうございました。
進まないね もう他のCPUのSIMDの話題もおkにしない?
他のCPUってARMのNEONとかか?
SSEのプリフェッチ命令を使っても効果が出ない。 使い方がわからないんだよな。
89 :
デフォルトの名無しさん :2010/09/16(木) 20:54:23
距離を測ってそれに合わせたタイミングで発行すればよろし
CPU固有の最適化になるわさ そらICCも_mm_prefetchを消したくなるわ
キャッシュが潤沢で ハードウェアプリフェッチが効いてる環境だと ソフトウェアプリフェッチは要らないんじゃないの?
Core2,、Core iのハードウェアプリフェッチの動作仕様を書いた 文書はあるのか?
1.ループの外でバッファの先頭を指定して_mm_prefetch_ntaする。 2.ループ内で、バッファ先頭から順に読んで処理し、_mm_stream_si128で書き出す。 このとき、CPUが気をきかせて、1ループにかかった時間から最適な距離を判断して、 キャッシュ汚染しないプリフェッチをハードウェアで自動的にしてくれたりする?
表記間違えてるけどそこは無視してお願い
95 :
デフォルトの名無しさん :2010/09/19(日) 13:38:02
for(i=0;i<16;i++) a[i]^=(d[i]+c[i])%16; このプログラムをSSE2で書きたいのですがわかりません。 教えてください。よろしくお願いします。
宿題か?
97 :
デフォルトの名無しさん :2010/09/19(日) 14:24:07
暗号を作っているんですけど高速化したいんです。メインループは for(k=0;k<500000;k++){ for(j=0;j<16;j++){ for(i=0;i<32;i++){ d[i]^=GF[mlt(FG[a[j]],FG[h[i][FG[b[j]]]])]; } } こんな感じなんですがGPGより4倍くらい遅いです。
99 :
デフォルトの名無しさん :2010/09/19(日) 14:49:48
あんろーるってなんですか? 128ビット単位なので必要のないループが減らせたら高速化できると思うので 基本的に行列演算の高速化だと思います。
iccでベタ書きして最適化オプション/pragmaを加えるだけでおk?
101 :
デフォルトの名無しさん :2010/09/19(日) 15:01:15
すみません、具体的にコマンドラインを教えてください。 使用環境はCygwin32,gcc4です。 コンパイラに任せてもSSE2命令に変換してくれるのでしょうか?
実験したいからとりあえずmltとGF,FGの型おせーて
>>101 iccならベタ書きの内積計算関数でdpps使ってくれたりするから多分いやもしかしたらいけるかもしれない
104 :
デフォルトの名無しさん :2010/09/19(日) 15:08:47
int N=256; static int GF[256];(GF(256)有限体の元) static int FG[256]; GF(256)の対数値 int mlt(x, y){ if(x==0||y==0) return 0; return ((x+y-2)%(N-1))+1; } です。よろしくお願いします。
105 :
デフォルトの名無しさん :2010/09/19(日) 15:13:44
int h[32][256]; 追加です。因みに for(i=0;i<16;i++) a[i]^=(d[i]+c[i])%16; の高速化だけでもいいです。
106 :
デフォルトの名無しさん :2010/09/19(日) 15:15:24
ループから外して式をばらすってことですか?>あんろーる
107 :
デフォルトの名無しさん :2010/09/19(日) 15:18:04
C言語からインラインアセンブラで呼び出したいと思うのですが、 うまくいきません。 moveq d,%xmm0 moveq c,%xmm1 paddb %xmm1,%xmm0 moveq a,%xmm1 pxor %xmm1,%xmm0 配列のデータをレジスタにセットするところもわかりません。
518 :デフォルトの名無しさん:2010/09/19(日) 14:20:02 for(i=0;i<16;i++) a[i]^=(d[i]+c[i])%16; このプログラムをSSE2で書きたいのですがわかりません。 教えてください。よろしくお願いします。 C言語からインラインアセンブラで呼び出したいと思うのですが、 うまくいきません。 moveq d,%xmm0 moveq c,%xmm1 paddb %xmm1,%xmm0 moveq a,%xmm1 pxor %xmm1,%xmm0 配列のデータをレジスタにセットするところもわかりません。
>>107 インラインアセンブラ嫌いだから組み込み関数で書くけどこんな感じ。
_mm_storeu_si128((__m128i*)a,_mm_xor_si128(_mm_loadu_si128((__m128i*)a),_mm_and_si128(
_mm_add_epi8(_mm_loadu_si128((__m128i*)b),_mm_loadu_si128((__m128i*)c)),_mm_set1_epi8(0x0f))));
111 :
デフォルトの名無しさん :2010/09/22(水) 06:24:35
>>110 の記事で256ビットを演算器の使い回しで実現するって部分で
128ビット幅の浮動小数点用と128ビット幅の整数演算用を使ったってのがよく理解できなかった
128ビットについては普通に浮動小数点用のを使って、
整数演算用が同サイクルに使われることがないから、
整数の加算乗算シフトとかを組み合わせて浮動小数点と同じことをしてるってことかな?
112 :
デフォルトの名無しさん :2010/09/22(水) 09:17:56
#include <stdio.h> #include <stdlib.h> int main(void){ unsigned long long int a,b; a=strtoull("0x1111111111111111",(char **)NULL,16); b=strtoull("0x2222222222222222",(char **)NULL,16); a=a^b; printf("%llu\n",a); return 0; } このプログラムをMMXを使って最適化したいのですがわかりません。 アセンブラで書くしかないのでしょうか。
>>110 つまりAVXはSSEより速くはならないってこと?
単精度の4次元ベクトルは扱うことがあっても8次元や倍精度とか使わないからなぁ
これの最速のSSEコードを教えてください
32ビットカラービットマップを24.8固定小数点で線形補間するコードです
自分で書いてはみたものの元のCより遅いので
typedef struct
{
union
{
unsigned char b, g, r, a;
unsigned long c;
};
} COLOR;
unsigned long Get(unsigned x, unsigned y, COLOR* Table, unsigned width, unsigned height)
{
COLOR c;
c.r = (
(Table[(y >> 8) * width + (x >> 8)].r * (0x100 - (x & 0xff)) + Table[(y >> 8) * width + (x >> 8) + 1].r * (x & 0xff)) * (0x100 - (y & 0xff))
(Table[((y >> 8) + 1) * width + (x >> 8)].r * (0x100 - (x & 0xff)) + Table[((y >> 8) + 1) * width + (x >> 8) + 1].r * (x & 0xff)) * (y & 0xff)
+ 0x8000) >> 16;
以下g, b, aと繰り返す
return c.c;
}
>>114 でCで実際に書いたときは乗算に[257][256]のテーブルを使用してました
116 :
デフォルトの名無しさん :2010/09/22(水) 14:40:16
257だと!?
117 :
デフォルトの名無しさん :2010/09/22(水) 21:10:04
このループはSSE2使っても早くならないですか? ていうかSSE2使えますか? for(j=0;j<16;j++){ for(i=0;i<16;i++){ d1[j]^=GF[e1[j][i]]; d2[j]^=GF[e2[j][i]]; } }
xorだけsimd使ってもなぁー d1の計算とd2の計算で2つスレッド使って別にループ回す方が それにしてもsynchronizeのコストがあるしなぁ
119 :
デフォルトの名無しさん :2010/09/23(木) 05:41:30
配列の配列ってアドレスがバラバラだからSIMD処理できないかも。
SSE使うかどうかに関係無く、参照アドレスが連続なる様にしておかないと キャッシュミスして処理速度がガタ落ちになる 昔ならともかく、今はどうしても明示的にSSEをしなければならない場合以外は コンパイラー任せでいいんじゃないの
SSEを使用しなければならない場合以外は
122 :
デフォルトの名無しさん :2010/09/30(木) 02:18:33
変数は全部unsigned charですがコンパイラでやるとSSE2命令にしてくれません。 丸投げですが、組み込み関数でもいいのでSSE2のアセンブリコードをお願いします。 for(j=0;j<16;j++){ a[j]^=(d1[j]+c[j])&0xff; b[j]^=(d2[j]+c[j])&0xff; buf[j]^=d1[j]; buf[j+16]^=d2[j]; }
またお前か
128*2でしか使えないのか 蓋を開けてみればAVXも残念なものだった
高々数万のCPUに過大な期待すんな。
現プロセスにおいてトランジスタ効率上げるための折衷仕様だから、 いずれ改善されるだろう
>>124 > 128*2でしか使えないのか
コアあたり、1クロックで256bitレジスタの加減算と積が出来ると思うんだけど。
>>122 じゃあ、こんな感じで。
__m128i *pa = (__m128i*)a; __m128i *pb = (__m128i*)b; __m128i *pc = (__m128i*)c;
__m128i *pd1= (__m128i*)d1;__m128i *pd2= (__m128i*)d2;__m128i *pbuf=(__m128i*)buf;
__m128i *pa = (__m128i*)a; __m128i *pb = (__m128i*)b; __m128i *pc = (__m128i*)c;
__m128i *pd1= (__m128i*)d1;__m128i *pd2= (__m128i*)d2;__m128i *pbuf=(__m128i*)buf;
__m128i va, vb, vc, vd1, vd2;
va = _mm_loadu_si128(pa); vb = _mm_loadu_si128(pb); vc = _mm_loadu_si128(pc);
vd1 = _mm_loadu_si128(pd1); vd2 = _mm_loadu_si128(pd2);
_mm_storeu_si128(pa, _mm_xor_si128(va, _mm_adds_epu8(vd1, vc)));
_mm_storeu_si128(pb, _mm_xor_si128(vb, _mm_adds_epu8(vd2, vc)));
_mm_storeu_si128(pbuf++, _mm_xor_si128(_mm_loadu_si128(pbuf), vd1));
_mm_storeu_si128(pbuf, _mm_xor_si128(_mm_loadu_si128(pbuf), vd2));
129 :
デフォルトの名無しさん :2010/10/02(土) 08:25:41
エラーがでるよ。こうやって書いて! _mm_storeu_si128((__m128i*)a,_mm_xor_si128(_mm_loadu_si128((__m128i*)a),_mm_and_si128( _mm_add_epi8(_mm_loadu_si128((__m128i*)d1),_mm_loadu_si128((__m128i*)c)),_mm_set1_epi8(0x0ff)))); _mm_storeu_si128((__m128i*)b,_mm_xor_si128(_mm_loadu_si128((__m128i*)b),_mm_and_si128( _mm_add_epi8(_mm_loadu_si128((__m128i*)d2),_mm_loadu_si128((__m128i*)c)),_mm_set1_epi8(0x0ff))));
130 :
デフォルトの名無しさん :2010/10/02(土) 08:27:27
あとこれも何とかして for(j=0;j<16;j++){ for(i=0;i<16;i++){ d1[j]^=GF[e1[j][i]]; d2[j]^=GF[e2[j][i]]; } }
131 :
デフォルトの名無しさん :2010/10/02(土) 09:40:15
エラーが無くなりました。早とちりでした。
132 :
デフォルトの名無しさん :2010/10/02(土) 10:02:14
buffに代入されません。 memcpy(&buff[32*k],buf,32);
133 :
デフォルトの名無しさん :2010/10/02(土) 10:18:44
マルチポストがいけないとは言わないが、アルゴリズムとコードと態度の糞っぷりが果てしない。
135 :
デフォルトの名無しさん :2010/10/02(土) 14:16:41
_mm_storeu_si128(pbuf++, _mm_xor_si128(_mm_loadu_si128(pbuf), vd1)); _mm_storeu_si128(pbuf, _mm_xor_si128(_mm_loadu_si128(pbuf), vd2)); pbuf--; buf[0]=*pbuf->m128i_u8; pbuf++; buf[16]=*pbuf->m128i_u8; clではコンパイル出来るのに、GCCだと共用体のメンバじゃないというエラー が出てコンパイルできません。なぜですか。正しい代入方法を教えてください。
136 :
デフォルトの名無しさん :2010/10/02(土) 14:43:21
_mm_storeu_si128(pbuf++, _mm_xor_si128(_mm_loadu_si128(pbuf), vd1)); _mm_storeu_si128(pbuf, _mm_xor_si128(_mm_loadu_si128(pbuf), vd2)); pbuf--; buf[0]=*pbuf->m128i_i8; pbuf++; buf[16]=*pbuf->m128i_i8; 書いてもらったプログラムなのでよくわかりませんが、128ビットの 共用体を2つ分使っているのではないかと思います。 ところで上のプログラムをclでコンパイルすると通るのに、GCCだと 共用体のメンバじゃないといわれてエラーが出ます。pbufからbufに 値を代入する正しい方法を教えてください。もしくはmemcpyでpbuf からbuffに代入する方法があったら教えてください。よろしくお願いします。
memcpyの使い方も知らない人はC言語の勉強からやり直した方が良いと思うんだ。 大体にして、スピードなんて後でいいだろ。 本当に良いプログラムなら指数的なオーダーで遅くならない限りみんな使ってくれるし、そんな良いソフトがオープンソースならガリガリに最適化してくれる人も現れるよ。
138 :
デフォルトの名無しさん :2010/10/02(土) 15:01:50
何かを習得するのって本当に難しい。使いながら解らない所を調べて いくという感じで。ネットで調べてるんだけどなかなかいい情報が 得られない。エラーメッセージの意味もよくわからないし。
何を調べてるのかしらないが、英語の資料を除外してるといい情報は出ないぞ いい情報は英語でしかないことが多い
>>114 を教えていただけませんか?
Cより高速化できる見込みがあるかどうかだけでも結構です
見込みはないです。
AMDを応援したいがAVX対応が1年も遅れるようじゃSandyBridgeを買わざるを得ない。
地雷踏みはIntel信者の団子にでも任せておけばいいじゃないか。
145 :
,,・´∀`・,,) ・・・→ -○○○ :2010/11/02(火) 19:37:28
SDE使えばAMDのCPUでもAVXのコードを実行できるんだから好きにしろよ むしろSandy Bridge出てからコード書こうと思ってるならどのみち出遅れてるから いっそBulldozerまで待ってやれよ
>>145 シミュレーションじゃ実行速度のメリットをまったく味わえないじゃないか。
俺は既にXOP向けのコード書いてるから実機(Bulldozer)は少なくとも買うよ。 BulldozerってSIMDユニットは結局1モジュールあたり4基(MMX×2、FMAC×2)だよな? FPではクロック当たり性能で差は付かなさそうだ。 あとは整数だが、FMAC側でも簡単な整数論理演算ができれば胸熱なんだが。 FP積和算の理論スループットは同クロックならSandy Bridge 4コア=Bulldozer 8コアで あとは整数
>>147 俺は素直に先に出るSandyを買うよ。
その先はAMDのFMA4とintelのFMAの動向が見えてきたら考える。
命令セットだけ見るとFMA4の方が良いが....
どっちも買えばいいじゃん。 Intel現行仕様の3オペランドFMAはAMDも「Bulldozer 2」で対応するらしい。 いっぽうIntelの4オペランドFMAの採用計画は不明。もともとIntelの提案仕様だしVEX空間にあるので 採用しない理由はないと思うが。 実際プログラム書いてみたけど3オペランドで困るケースって本当に.少ないんだわ。 しかもほとんどのケースでvfmadd231psで事足りる(132, 213は殆ど使わない) むしろ3オペランド版のほうが1バイト短い。 どうせなら4オペランド版はimm8の残り4ビットを何かのオプションとして使いたいよね。 vbroadcastss + fmaddpsを1命令に纏めることができるとかさ。 Intelが3オペランド仕様に修正した技術的な理由はなんとなくわかる。 iaca使ってみればわかるが、AVXで4オペランド命令は複合命令ばっかしだぜ。 Simpleデコーダのロジックケチりたいんだろ。
>>149 AMDがintel仕様の3オペランドのFMAに対応するってマジか?
ソースきぼんぬ。
> These patches add support for upcoming bdver2 AMD processors:
> BMI (Bit Manipulation Instructions)
> TBM (Trailing Bit Manipulation)
> FMA3 (three operand FMA) instructions
>
> The public specifications for BMI and TBM are in progress (they are
> today available under NDA). They will appear in one of the AMD64
> Architecture Programmer's Manual Volumes 3-6. I can post the
> mnemonics definitions if needed. The FMA3 specification is documented
> in
http://software.intel.com/en-us/avx/ http://archives.free.net.ph/message/20101015.184549.56493850.ja.html bdver2ってのが22nm版なのか後期リビジョンなのかが不明
>>151 thx
FMAの命令セットの分裂は避けられたってことか。
こうでそ AMD「SSE5で3オペランドFMAをサポートします」 ↓ Intel「うちもそっくりそのまま+addsub命令も加えて4オペランドFMAをサポートします」 ↓ AMD「SSE5やめてAVX互換で仕切りなおします。FMAはIntelさんと同じ4オペランド方式になります」 Intel「デコードコストが大きいのでやっぱ4オペランド当分やめて3オペランド(新方式)でやります」 ↓ AMD「え?」 Intel「え?」 てか、SSE5にあったCVT16はXOP→VEX(Intelもサポート)という流れになってるし IntelとてAMDはAVX普及に協力してもらう立場。 摺り寄せは当然やるでしょう
intelが元々考えてた4オペランドと AMDが一番初めに考えてた3オペランドの 命令の詳細を見たことが無いけど、 これって 今の AMD FMA4 / intel FMA と同じ?
デスクトップのBulldozerは4月以降か、思ったより速いよ。
ESが12月で4月に生産とか本当に出来るのかあやしい
ベンチマダー?
> デスクトップのBulldozerは4月以降か、思ったより速いよ。 早いが速くない
>>147 斜め下の期待を裏切らないAMDの事だから
直近: Sandy Bridge 4コア vs Bulldozer 4or6コア(2or3モジュール)
将来: Sandy Bridge 6コア vs Bulldozer 8コア(4モジュール)
とかってなりそうな気がしてる。そうするとFPで負けそう。
162 :
デフォルトの名無しさん :2010/11/15(月) 08:27:26
将来512bitとか1024bitのレジスタ作ったとき VEXプリフィックスでどうやって指定するのかね? Lは1bitしか用意されてないし 全然別系統の命令ということにするのかね?
3ビット余ってるって言ってたところ(3バイトVEXの第2バイト)使うんでしょ 長さ指定があっちゃこっちゃ散らばって、汚いなさすがイッテルきたない
164 :
デフォルトの名無しさん :2010/11/15(月) 11:03:35
FPUとSSEを交互に使うと待機時間が減って高速化できるとどこかで見たことがあるんだが FPUとAVXを混ぜると速くなるとかってあるのか? Pen4からSSEのユニットでFPUをシミュレートしてるらしいし現状のAVXはSSEを2個並べてシミュレートしてるらしいから無理なのかな?
>>165 Pentium IIIのときはx87ユニットとSSEユニットが分かれてて論理レジスタも別だから
並列動作させることができてそういうことも起こりえた。
今となってはx87全面禁止にしたほうがいい。
128bit浮動小数が普及するのはいつになるのだろう
>>166 x87から切り捨てるならもっと古いx86は使わずAMD64やIA64を使えという話になってしまう。
互換性より速度が重要ならそれでいいかもしれんが。
別にx87が動かないわけじゃない。速くないだけ。
>>167 128bit, 256bit, 多倍長, などのライブラリを自作してるオレからしてみると
早く普及してほしい。
ついでに、128bit 整数も欲しい。
が、用途が限られすぎて普及しないと思う。
>>170 俺もライブラリ作っているんだけれど、範囲被ってたりしないかなあ。
それはオープンソース?
今の所FORTRANのREAL*4ぐらいか?128ビット浮動小数点の利用価値が高いのは C/C++でもlong doubleが128ビット長になる(規格には入らないだろうが)可能性はあるな
REAL*4でなくてREAL*16だろ どちらにしろ標準FORTRANの文法から逸脱しているのでコンパイラの独自拡張になるが
>>171 公開してない自分用。
趣味の数値計算、組み合わせ計算、確率計算で使用。
ライブラリと言ってもlibやdllじゃなくて基本はソースのまま(cppとasm)。
asm部分は最近は64bit用しかメンテしてない。
一通りの関数は作ってあるつもり。
多倍長の乗算はフーリエ変換、
除算、ルートと一部の無理関数はニュートン法、
円周率はガウスルジャンドル、
他の無理関数はテーラー展開。
1100|0100 RXBm|mmmm||Wvvv|vLpp 1100|0101 Rvvv|vLpp VEXと16進数の変換に一瞬頭が混乱する もう歳だな・・・
64bitだとdoubleのシフト・回転も一発で出来て楽だな
Intel FMAの231, 213, 132ってのを似非4オペランド形式で記述できるYASM用マクロ書いてみたけど こういうの需要ある?
そーいうのはいちいち他人にお伺い立てるんじゃなくて、 自分が公開したいしたくないで決めるもんだ
SSEとあんまり関係ないかもしれないけど、 普通のCPUの浮動小数点演算回路って 倍精度と単精度が別々にあるの? それとも倍精度の一部を使って単精度にしてるかそれか単精度2つで倍精度作ってるのか、 それとも倍精度はかけるクロック数が違うだけで回路は共通なのか どうなんでしょうか
SSEみたいなものを除けば、単精度演算回路自体を省略している方が多いんじゃないかと。
181 :
デフォルトの名無しさん :2010/12/19(日) 07:45:58
SSE/SSE2で全ビット1にするにはどうしたらいいの? 論理否定命令とか見当たらないんだが・・
>>2 IntelはもうMMX使うの止めてくれ、って言ってなかった?
183 :
181 :2010/12/19(日) 08:17:33
_mm_cmpeq_pdでいいみたい
>>181 ,183
_mm_cmpeq_ps, _mm_cmpeq_pdだとNaNの時に1にならないから、z=_mm_setzero_pd();m=_mm_cmpeq_pd(z,z)
ってするか、_mm_cmpeq_epi32を使う。
あともっと手っ取り早いのは_mm_set1_epi32(0xFFFFFFFF)とする。
よく使われるならL1に入っているはずだからこれが一番速い。ミスヒットすると一番遅いけどね。
>>184 ベンチとってみた
// case 1
f0 = _mm_setzero_ps();
for( uint_t i = 0; i < UINT_MAX; ++i )
{
const __m128 f1 = _mm_cmpeq_ps( _mm_setzero_ps(), _mm_setzero_ps() );
f0 = _mm_add_ps( f0, f1 );
}
// case 2
f0 = _mm_setzero_ps();
const __m128 f1 = _mm_setzero_ps();
for( uint_t i = 0; i < UINT_MAX; ++i )
{
const __m128 f2 = _mm_cmpeq_ps( f1, f1 );
f0 = _mm_add_ps( f0, f2 );
}
// case 3
f0 = _mm_setzero_ps();
for( uint_t i = 0; i < UINT_MAX; ++i )
{
__m128i i1;
const __m128i i2 = _mm_cmpeq_epi32( i1, i1 );
f0 = _mm_add_ps( f0, _mm_castsi128_ps(i2) );
}
// case 4 f0 = _mm_setzero_ps(); for( uint_t i = 0; i < UINT_MAX; ++i) { const __m128i i1 = _mm_set1_epi32( 0xffffffff ); f0 = _mm_add_ps( f0, _mm_castsi128_ps(i1) ); } // 結果 case 1: time = 6.090190 case 2: time = 4.637256 case 3: time = 4.636985 case 4: time = 4.620227 case3が良さそう。 つーか、case1よりcase2の方が速いのが解せない。 _mm_setzero_ps()って、何か効率の悪い方法で0生成してるの?
アセンブラ見てみろよ。case1はたぶんこうなってるから。 xorps xmm0, xmm0 xorps xmm1, xmm1 cmpeqps xmm0, xmm1 命令数が増えてデコーダネックってところだろう。 いくら同一レジスタ間のxorが実行ポートを使わないだのレジスタリネーミングのヒントになるだの言っても デコーダは通るわけだからな
Case1は、_mm_setzero_ps()の呼び出しがループの外に出されている以外は 大体そのままの形でした。 Case2は、「const __m128 f2 = _mm_cmpeq_ps( f1, f1);」自体 ループの外に出されちゃってました。 つまりベンチが失敗してました、すんまそん(T_T)
189 :
デフォルトの名無しさん :2010/12/20(月) 05:18:48
そういやこのスレ立てたのは俺だった 細菌CUDAに凝ってSSE使うケース減ったな
細菌CUDA……バイオテロみたいだ
CUDA速いの?
使い方による 間違えれば効果なし 使えるアプリ使えないアプリの見極めが必要 はっきり言って使いこなしはかなり難しい
Cellより使いづらそうに見えるんだが気のせいだろうか?
Cellよりまし。ソースは私。
195 :
デフォルトの名無しさん :2010/12/20(月) 17:36:46
具体的にはどうマシなわけ? Cellの難しさなんてSSE+α程度だったと記憶してるけど?
SPUはパイプラインを切った貼ったやらんとパフォーマンスでないのよ。 単に動かすだけならSSEより楽なくらいだけど。 CUDAはFermiになるとキャッシュが利くから結構横着できるからね。
SSEとか無関係だし。 VC7.1の場合、大雑把にloopの中身。 case 1 movaps xmm0,xmm1 cmpeqps xmm0,xmm1 addps xmm2,xmm0 case 2 cmpeqps xmm0,xmm0 addps xmm1,xmm0
明らかに変数宣言をループの外に出したほうがいいな てかstatic constじゃ駄目なのか? AVXでOpcode空間に余裕ができたからNANDやNORがようやく実装されるんじゃないかと期待
>>198 あれ、団子の割にそんな事言っちゃうの?
それとも俺が確認不足かな。
最適化を有効にしたらループの中で変化しない演算はループの外に出るはずだし
static constにしなくても_mm_set1_pxxみたいのは定数のロードになってるはずだけど。
ただし、
float PI=3.14;
__m128 PI4=_mm_set1_ps(PI);
でこのあとPI4しか使わなければPI4は定数として用意されるけれど、PIを別の場所で使っているとオブジェクトにはPIだけ用意されてPI4を作り出す為にシャッフルする事が稀にあるのは知ってる。
あとgccなんかはstatic const __m128とかやろうものならむしろ無駄なコードを吐く。
gccを使うべきでない理由がまた一つ増えたな。
ぶっちゃけアセンブラでしか弄ってないもんで。 スカラ演算ベースだったらCでやっちゃうけど(最近のVC++は本当に優秀) Intrinsicsは機械語とほぼ1:1で対応してる分、最適化が阻害される部分もあるんで 整数のコードに関しては最近はCでスカラ演算ベースで書いてアセンブリコード 吐き出してからそれを並列化するようなやり方でやってる。 ビット演算を組み合わせるところなんか、本当にVC++は賢い。
> Intrinsicsは機械語とほぼ1:1で対応してる分、最適化が阻害される部分もあるんで ここに完全に同意。 ベクタ長を意識しなきゃいけないシーンが多過ぎる事、命令が変態過ぎてコンパイラが自動ベクトル化しづらい事、Intrinsicsと1:1なせいで自動的な最適化があまり望めない事、 そこら辺はGPGPUの方が若干目があるなあと感じている。
intrinsics のいいところは、値がメモリに割り付けられててもレジスタ上にしかなくても同じコードで済むところ。
Visual Studio 2010 SP1でXOP/FMA4/LWPなどのAMD独自新命令に対応の模様
AVX 第3版 以前 VFMADDPD __m128d _mm_fmadd_pd (__m128d a, __m128d b, __m128d c, const int ctrl); VFMSUBPD __m128d _mm_fmsub_pd (__m128d a, __m128d b, __m128d c, const int ctrl); AVX 第4版 以降 VFMADD???PD __m128d _mm_fmadd_pd (__m128d a, __m128d b, __m128d c); VFMSUB???PD __m128d _mm_fmsub_pd (__m128d a, __m128d b, __m128d c); VS2010 SP1 FMA4 intrinsics VFMADDPD __m128d _mm_macc_pd (__m128d a, __m128d b, __m128d c); VFMSUBPD __m128d _mm_msub_pd (__m128d a, __m128d b, __m128d c);
> VFMADDPD __m128d _mm_fmadd_pd (__m128d a, __m128d b, __m128d c, const int ctrl); Intel FMAに第4引数なんて元々ないよ。imm8の3つ目のソースオペランドとして使って残り4ビットは予約。 AMD版FMAの_mm_macc*って命名則はSSE5由来だが対応する命令はAVX第3版までのFMA仕様にすげ変わってる。
Sandy発売したのに
ベータ版のサービスパック入れられない人もいるのよ
俺はAVXの先に興味を持ちました。 Bulldozerまだかよ シミュレータでさっさと出して欲しいですな。
Intelのマニュアルのハードコピーって無くなってたんだ。 AVX版が出るまで待とうと思ってずっと我慢してたのに。
GARAPAGOSにPDFリーダーついてたら10インチ買うわ。
配布してる同期ソフト経由で転送してPDF見られるらしいけど、見開きで表示できなかったり 画像としてしか表示できなかったりして、色々と残念な出来らしい。 画面解像度だけみて大きくて見やすいだろうからとPDF目的で買うとガッカリするレベルだそうな。
ここで薀蓄垂れてる奴なら、ハックして自家製ビューア走らせるくらい朝飯前だろ?
やっぱりAdobe Readerそのものが必要だな。 Atomタブレット待ちか。
AVX試した奴いないの? linuxならKernel最新にすりゃできるよな? 報告よろ
別に開発だけなら今回はシミュで十分だしな。 prefetch距離とかの調整くらいはやりたいけど。
団子は自作板の方でSandybridge出たら買って遊ぶとか言ってなかった? Win7SP1待ち?
口先だけで、金も腕もないってとこなんじゃないの
222 :
デフォルトの名無しさん :2011/01/15(土) 01:41:36
>>216 GALAPAGOSにそこまでするだけの価値を見いだせない。
機能限定されすぎたタブレットPCのできそこないにすぎず、ちょっと機能が増えただけの電子書籍専用端末でしかない。
Androidマーケットでアプリ追加することすらできないんだぜ?
サイズ的には良い感じなんだけどね。Mebius辞めて何を作るかと思ったらこれだからな。 アップデートに期待したいところだが。 実機環境は枯れるまで待ち、というかノートの春モデル待ち。 何か問題出た場合にソフトの不具合なのかハードの不具合なのかわからないってのが一番厄介だから 自作をすべきではない、という経験論。
224 :
デフォルトの名無しさん :2011/01/15(土) 18:35:14
なんで AVX には bsr/bsf が無いんだよ。
なんで必要だと思ったの? ただ4並列/8並列でbsr代替はできるよ。 (v)cvtpi2psで指数部抽出できるだろ。あとはわかるな。
ローテートください
227 :
デフォルトの名無しさん :2011/01/16(日) 11:21:36
>>225 将棋のbitboardで必要だろう。jk
そんなどうでもいい用途向けに専用命令つくれとか もっと意義のある事をあげろよ
圧縮やら浮動小数やらいくらでもある。 x86始め、よく実装されているのは必要とされているからだ。
CPUに実装されないのは「必要とされていないから」だろ。
>>230 何らかの事情で出来なかったも考慮したほうがよいのではないでしょうか。
そういう場合は代替がある。
このスレで一番賢くてSSEに詳しい人に質問。 __m128i ptn = { 0,4,8,12, 16,20,24,28, 1,5,9,13, 17,21,25,29}; __m128i ptn2={ 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15}; __m128i v0 = _mm_load_si128((__m128i*) p1); __m128i v1 = _mm_load_si128((__m128i*) p2); __m128i v2 = _mm_shuffle_byte(v0, v1, ptn); ←v0とv1を連結して8bit x 32個の要素の中からptnで指定したものだけを並べる __m128i v3 = _mm_load_shuffle_byte((__m128i*) p3, ptn2); ←8bit x 16個の要素をメモリから読み出し、ptn通りに並べ変える SSEにこんな感じの命令はありませんか? 無い場合、SSE3までの範囲で代替しようとすると、どのくらい複雑になって遅くなりますか?
日本ローカルのボードゲームの解法ごときに貴重なOpcode空間を割くのは無駄だからにきまってるだろ とはいっても、cvtdq2psのような命令がある以上、4並列のビットスキャン回路は実装されてるわけだが。
>>233 本当に任意のパターンであればSSSE3が使えるかどうかによってだいぶ変わる。
SSSE3が使えない場合はパターンの規則性によってだいぶ変わる。
233に特化したやり方でこのスピード、ちょっとでも並びが変わると格段に遅くなる
とかあり得るので、「233の場合」という質問はアリでも「233みたいな場合」とか曖昧な質問は無しな。
できれば
>>233 のパターンに限定しない方向でお願いします。
>>233 1行目が釣りくせえええええ
packssdwの32ビット値の下位16ビットの最上位が1の場合って飽和処理されるんだっけ?w
pshuflw/pshufhwで並べ替えてからpshufdで詰めるか
あとは8ビットおきにマスクしてpackuswbで詰めればOK
>>236 限定しないなら答えようが無い。
基本SSSE3の_mm_shuffle_epi8とSSE2の_mm_shuffle_epi16, _mm_shuffle_epi32を使ってどうにか出来なそうなら諦めるしか無い。
ちなみに複雑さに興味があるようだから例を挙げておくと
ptn2はshuffle x 2+unpack x 3回で作れる。
ptnの計算量は一度ptn2 x 2+unpack x 1回になるので、素直にバイト配列でも良いと思う。
>>236 方法など無い。テーブル参照して16回ロードすべし。以上。
ただ、32ビットずつ纏めてからmovdでxmmレジスタに転送したほうが速いかも知れないね。
>>237 ん?そんな簡単に出来るの?
packsは飽和処理がうざいよな。飽和無しバージョンを作って欲しい。
わかりました。SSEって不便なんですね。
>>241 Core1世代は諦めろ。
任意のパターンはshuffle_epi8が使えないとどうにもならんし、逆に使えればptn2は1発だ。
Intel製のCPUとかちょっと使いたくないんです。 AMD製に同様の命令が追加されたりしませんかね?
VS2010のデバッガ上でYMMレジスタが表示できないんだけどなぜ? [AVX] と [AVX 浮動小数点] がグレー表示になってる。 CPUはSandyBridgeでWindows 7 のSPもあてたんだけど。
>AMD製に同様の命令が追加されたりしませんかね? 釣り確定
246 :
デフォルトの名無しさん :2011/01/18(火) 02:44:51
>Intel製のCPUとかちょっと使いたくないんです。 煽り確定
使いたくないならコンパイラの最適化に丸投げでいいんでねーの
248 :
デフォルトの名無しさん :2011/01/18(火) 23:51:39
プリフェッチ命令は1回の発行で何バイト読み込むんですか? 32バイトから128バイトという曖昧な情報もあれば、 1ライン読み込みなので64バイトと言う情報もあります。 命令なので後者のほうが正確のような気がするのですが、認識は合っているのでしょうか?
CPUの型番で違う、ってのが答えだったような。
Pentium IIIは32バイト Athlon XPは64バイト Pentium 4は128バイト Pentium Mは64バイト だったような
251 :
デフォルトの名無しさん :2011/01/19(水) 00:23:55
>>249 となると、
Pen4はラインサイズが64バイトなので64バイト、
C2Qも同様に64バイト、ということでよろしいのでしょうか?
>>250 ありがとうございます。
微妙に情報が食い違っていたりするので、
もう少し調べてみます。
CPUIDでキャッシュラインのサイズ調べるのが確実だよ t1 = L1D t2 = L2 nta = LLC ただしPentium 4はt1でもt2でもL2までしかフェッチされない
↑訂正 t0とt1読み替えてね
>>253 C2Dは64バイトでした。
他のマシンでも調べてみます。
ありがとうございました。
FMAってIvy Bridgeになったら搭載されるの? それとももっと後?
>>256 ボケたな・・・
t0 = L1D (Pentium 4は例外)
t1 = L2
t2 = L3(LLC)
nta = L1D(Non Temporal)
260 :
デフォルトの名無しさん :2011/01/26(水) 20:48:00
MASMでAVXプログラミングしてる人いませんか? MASMで32バイトアラインメントで静的変数を確保したいんだけど、 方法がわかる人いませんか? VS2010付属の ml64.exe です。 align 16 ならできるんだけど、 align 32 はダメみたい。 今はビルドしてずれてたら詰め物を手動で入れてます。
IntelはYASMがお墨付きだしMASMなんて使わないに越したことはないけど。 ちなみにNASMは色々腐ってるので使用禁止レベル。 たとえば、コード上でalignマクロを使うと、VEXが常に3バイトだと仮定して詰め物をするんだよね align 16 vxorps ymm0, ymm0, ymm0 vxorps ymm1, ymm1, ymm1 vxorps ymm2, ymm2, ymm2 vxorps ymm3, ymm3, ymm3 align 16 ;; ←ここが問題
何も問題ないけど use64 vxorps ymm0, ymm0, ymm0 align 16 vxorps ymm8, ymm8, ymm8 align 16 db 0ffh 00000000 C5FC57C0 00000004 90<rept> 00000010 C4413C57C0 00000015 90<rept> 00000020 FF
ん?直ったのか?
>>181 今更だが...
浮動小数点例外を有効にして無いならこれでもいい。
_mm_cmpnlt_pd
_mm_cmpnlt_ps
AVXでYMMをすべて1にする場合は、
VCMPTRUEPD
VCMPTRUEPS
というぴったりな命令がある。
(VCMPNLT_UQPDとか他にもいろいろあるけど)
>>261 YASMだと align 32 が使えるの?
FP比較は遅いからvpcmpeqb *してvpinsertf128でいいよ。 128ビットまでならロードしたほうが速いかも。ブロードキャストすればデータセクションの容量も食わないし
268 :
|ω? :2011/01/26(水) 22:32:49
4096
>>266 ロードは128bitも256bitも同じ速さだと思う
いいや。 Loadユニットは128ビットが2本。 256ビットロードは1ポートを2サイクル分消費する。 あと、32/64ビット→128ビットのブロードキャストはロードユニットだけでできるので わざわざ大きいテーブル用意する必要も無くなる。
団子さんも勘違いしてる事が稀によくあるから、自分で実際に検証してみた方がいいぞ。
>>270 ヒント
32/64ビット→256ビットのブロードキャスト
vmovdqa (128b load) Load×1 vmovdqa (256b load) Load×2 vbroadcast{ss,sd} (128b) Load×1 vbroadcast{ss,sd,f128} (256b) Load×1+ FP_Permute
団子さんってトリップ検索以外もやるの?
実質6年前に辞めてるけど?
団子さんの目って ´ ` ですか? それとも ・ ・ ですか?
>>266 レイテンシはあるけどPort1を1クロックだけ使うだけだから
使える場面は多いかと。
最良は3つを使い分けることか。
| Num of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | |
------------------------------------------------------------
| 2^ | | | | 1 | 1 | X | X | | 1 | CP | vbroadcastss ymm0, dword ptr [0x0]
| 1 | | | 1 | | | | | | | CP | vcmpps ymm0, ymm0, ymm0, 0xf
| 1 | 1 | | | | | | | | X | | vpcmpeqb xmm0, xmm0, xmm0
| 1 | | | | | | | | | 1 | | vperm2f128 ymm0, ymm0, ymm0, 0x0
FP演算の場合はport1とport2は利用頻度高くてport5はレジスタ間mov(AVXの場合は基本的に使わない)や シャッフル、ブレンド程度しか使わないから、port5積極利用で良いと思うけどな。 これも場合によるか。
>>277 ・の方。一行目のは公家が描いてる眉と同じ。
AAでは上が見切れてるけど烏帽子被ってる。
麿は団子が食いたいのじゃ
>>279 負けず嫌いなだんご。
だんごより大福の方がうまいし。
うるせえおれはだんごがくいたいんじゃ というか、256ビット(SIMD-FP)でALL-Fなビットパターンが必要な処理って何があるんだ? 絶対値をとるために0x7FFFFFFFとかならまだわかるんだが。
多くのCPU向けにSSE2までに制限してプログラムを書いてるんだけど Core2以降がそれより前のものと比べてSSE1〜4.1が急に倍速化してるけど何か革新があったの?
タイムスリップして来た人乙 64ビットSIMDユニットで128ビット命令を2サイクルかけてたのが128ビットで1サイクルになった。
上位下位128bitをまたいだPermute命令がほしかった。 VPERMPD ymm1, ymm2/m256, imm8
単純にSSEx2ってわけじゃないのが使いづらい。 パック、アンパック、cvtが面倒。
AoS推奨
仮想環境でAVXは使えないのか ホストOSは仕事の都合上古めのLinuxじゃないと駄目なので ゲストで使いたいのだがcpuidのフラグが立たん
xgetbvのOSサポートのフラグじゃなくて? cpuidによるCPU対応のフラグも立たない?
そうなんですよ ホスト(RHEL5)だとOSXSAVE以外の必要なフラグは立ってるのだが ゲスト(SL6beta on VMWare Player)だとAVXのフラグすら立たない
Win7のSP1がもうすぐのようだな これでAVXガンガン効かせられる訳だ ったんだがな
SIMD命令ってなんで高級言語でかけないんだ GPUでは当たり前にできるのに
OpenCLでかけるようなるとかならないとか。。。
どっちだよ
intrinsics で充分だろ。
x86デコーダが適当な命令をSIMDに読み替えてくれれば解決 名付けてウルトラスーパースカラー
>intrinsics で充分だろ。 高級言語だからARMでもPowerPCでもコンパイル通(ry
石に依存する部分をコンパイラに丸投げするなんて信用できねえ。 というか、データ構造の設計がしにくくなるから、絶対に嫌。
NASM/YASMのマクロの構造体機能なにげに活用してるわ
303 :
デフォルトの名無しさん :2011/03/06(日) 20:52:16.61
__m128を動的に確保するには_aligned_malloc()を使う。 __m128をメンバに持つクラスAも_aligned_malloc()を使う必要があるのは まあ許すとして、 クラスAをメンバに持つクラスBも_aligned_malloc()を使う必要があるの? もしそうなら、とてもライブラリ作りにくいんだけど、そういうものなのかな?
_mm_movelh_ps()と_mm_movehl_ps()って なんでストアされる組み合わせが逆なの? 嫌がらせ?
>>303 そういうもんです。
__m128を少量メンバにするならdoubleやfloatで良いし、
大きな配列ならクラスの中で動的確保しる。
>>303 まず、根本的な問題として、C++なんか使うべきじゃあない。
クラスなんて非効率なものを使うのに、効率重視のintrinsics使うのはおかしい。
>>303 使えるなら、__declspec (align () )
>>306 クラスだから非効率は間違い
作り方によって効率的にも非効率的にもなる
>>306 今時はHLSLだって、クラス使うのよ
時代は変わっていくんだよ
>>307 それヒープには効かないのよ
xmmintrin.hに_mm_alloc()って有るはずだけど、使えない環境ではこんな感じでやってるぜ void * aligned_alloc(int count, int align_bytes) { void* addr = malloc(count + align_bytes); int offset = (int)addr & align_bytes; addr = (addr + align_bytes) & ~(align_bytes - 1); ((unsigned char*)addr)[-1] = offset; return addr; } void aligned_free(addr) { free(addr - ((unsigned char*)addr)[-1]); } C++を使いたい理由は明解だ。 _mm_add_ps(a, b)って書くよりa + bって書きたいじゃん。 つか、virtual継承さえ使わなきゃクラスってそんなに重たくならんよ。
AVXを試してみた 不良チップセットでだけど win7、VC2010expressイントリでコンパイルし、除算がSSE2の倍かかるんだが…
>>311 除算はご丁寧に128bitずつやってる糞仕様だから
ニュートン法を使った方が最後の1ビットまで計算しても速いと思うよ。
Intelはマジこういうのやめてほしいけどね。正常進化を阻害すると凝った事する訳じゃないのにプロセッサ特有の最適化が必要になっちゃって、Pen4の二の舞。
c++ならtryが出来るよので、俺はnewを使うよ。 >C++を使いたい理由は明解だ。 >_mm_add_ps(a, b)って書くよりa + bって書きたいじゃん。 > >つか、virtual継承さえ使わなきゃクラスってそんなに重たくならんよ。 gccなら、オーバーロードしなくてもそのままで使える。
>>312 除算はスーパーコンピューターだって遅いんだよ。
AVX除算速度と、回路規模、コスト、消費電力、クロック、開発期間、....
を天秤にかけて今の仕様になってんだよ。
ただ1個の要素だけ見て糞仕様とか、ド素人丸出し。
315 :
311 :2011/03/09(水) 22:00:37.52
SSE2の除算より遅いと書いたと思うが 素人丸出しか? AVXのが2倍速いとふつう思わんか? 素人で悪かったな
>>315 そりゃ256bitを128bitずつ2回に分けてるんだから当たり前だ。
317 :
311 :2011/03/09(水) 22:16:46.51
>>316 SSE2でやっても128×2でやるんだから同速だろ
そういう素人意見が聞きたいんじゃないんだが
>>317 128bit 単精度 スループット14 レイテンシ14
256bit 単精度 スループット28 レイテンシ29
実行時間を計ってみた divps xmm0, xmm1 183クロック vdivps xmm0, xmm0, xmm1 183クロック vdivps ymm0, ymm0, ymm1 203クロック 確かに異常に遅いな。 エラッタがあってマイクロコードで実行してるとか?
まあ、普通は除算は使わないようにするわな。
>>319 普通の数じゃないと極端に遅いみたいだ。
普通の数だと
divps xmm0, xmm1
12.7クロック
vdivps xmm0, xmm0, xmm1
12.7クロック
vdivps ymm0, ymm0, ymm1
25.3クロック
くらいだった。
値によって変わる模様。
インテルのドキュメントには範囲じゃない記述だったので
値によらずに同じクロックかと思ったのだが。
>>311 や
>>312 が何を騒いでるのか意味不明。
128bitの場合、 割る数、割られる数のどちらかが 0.0, NaN, ∞ の時は9クロックくらい。 割る数が2^nの時も9クロックくらい。 結果がアンダーフローや非正規数の場合と、割る数、割られる数のいずれかが非正規数の場合は183クロックくらい。 結果がオーバーフロー、割る数と割られる数が同じ、等は普通どおりの時間。
せめてSIMDだけでもいい加減デノーマルやめてほしいわww
>>323 デノーマルも不要だが、
個人的には無限をなくしてほしい。
異常値検出のNaNのはずが、
無限があると、大小比較が出来てしまっておかしいことに。
0.0がプラスかマイナスかなんて意味が無いのに、
1.0/0.0 が+無限、
1.0/-0.0 が−無限、
で、1.0/0.0 > 1.0/-0.0 が成り立ってしまう。
これを決めた人は頭が悪すぎる。
あの子の性癖はアブノーマル
326 :
311 :2011/03/10(木) 22:03:22.76
>>324 1.0/0.0 > 1.0/-0.0
これ成り立つんだけど
>>326 成り立つから良くないと書いてるんだけど。
328 :
311 :2011/03/10(木) 22:50:16.74
y=1/xの話だよ x=0近傍での話 実際に発生しうるってことね
>>324 基本的に入力が悪い場合は入力の責任にできる環境にあるので今まで出くわした事が無いが、
確かに使いたい場面が滅多に無いのに凝ってるのはひどい仕様だな。
ただ-0.0はSIMDで符号ビットをマスクするために使わせてもらっているので無くさないで欲しいw
SSE2からは_mm_castsi128_ps(_mm_set1_epi32(0x80000000))ってできるので、
SSEの時に適切にintからキャストする方法を用意しなかったIntelが悪いんだけどな。
>>328 +0.0 と -0.0 がある理由は、
単に符号反転がしやすい為。
実際、+0.0 = -0.0 が成り立つので、
+0.0 と -0.0 は同じ値の別表現だという意味である。
ところが、除算をするといきなり大小が大きく違う数になってしまう。
一貫性がまったくない。
Unordered にしておけば良かったのに、
何を血迷ったか Ordered にしてしまった。
Unordered だったらここまで不満は無かった。
331 :
311 :2011/03/10(木) 23:06:20.74
>>330 >>除算をするといきなり大小が大きく違う数になってしまう
数学的にそれが答えだから仕方ないでしょ
>>331 数学をしらない人間が数学を語るとは.....
数学的には、
+0と-0があって、同じもの同士を引いて+0にはなるが-0にはならない
なんて非対称な代数系は普通は使わない。
実数から0を除いたものに、±0と±∞を足したものは、
まともな代数系にならないことくらい周知の事実だ。
コンピューターも数学ももうちょっと勉強しなさい。
ド素人クン。
333 :
311 :2011/03/10(木) 23:14:21.02
考えられる実装は以下
A. +0と-0を同一視、+∞と-∞を同一視でUnordered、0による除算は∞
B. +0と-0を同一視、+∞と-∞は別でOrdered、0による除算はNaN
>>333 lim_[x→1.0] {1/(x-1.0)}
これは、xがプラス側、マイナス側のいずれから近づくかで+∞、-∞のどちらに発散するかが決まる。
ところが、コンピューター界では 1.0/(1.0-1.0) は-∞ではなく+∞だと定めている。
これには数学的根拠は全くない。
>>334 フィールズ賞をとったことが無いって意味では素人かもね。
つーか-0.0なんてどうやったら演算結果に出るんだよw 意図的に使わなければありえないだろ 個人的には 1.0/0.0=+Inf -1.0/0.0=-Inf 1.0/-0.0=NaN -1.0/-0.0=NaN にしてほしい
338 :
311 :2011/03/10(木) 23:37:38.58
0.0は限りなく0に近い切り捨てられた値として、-0.0は完全な0としてみなす仕様が欲しいってこと
>>337 ゼロ以外の普通の値に対して、
a*(b+c) とするだけでも出てくる可能性がある。
どうせ無限なんてでてくるのは異常値なんだからNaNで良いよ。 NaNはたくさんの種類が作れて、 勝手に自分で意味をつけられ、 その意味を伝搬していける。 中途半端な仕様の無限なんて不要。
>>340 bとcが正規数ならεはDBL_MINと同じか大きいから
abs(b+c)>=DBL_MINかabs(b+c)=0.0
だろ?
abs(a)<1.0だとしても計算時にデノーマルするだけで格納される値は
abs(a*(b+c))>=DBL_MINかabs(a*(b+c))=0.0
じゃないの?
具体的にはどんな値を入れれば出るんだ?
>>342 a=-1.0
b=1.0
c=-1.0
>>343 b+c= 1.00000000000000 + -1.00000000000000 = 0.00000000000000
a*(b+c)= -1.00000000000000 * 0.00000000000000 = 0.00000000000000
な気がするけどちょっと試してみる
お、できた 俺の認識が間違ってたみたいですまん double a, b, c, d; a = -1.0; b = 1.0; c = -1.0; d = a * (b + c); if(d < 0.0){d = 2.0;} だとdは2.0じゃなくて-0.0のままなのが納得いかないけどw
>>345 -0.0 と +0.0 は同一視の為、-0.0 < +0.0 は偽で、
-0.0 = +0.0 が真になる。
>>323 デノーマル数を0にしちゃって計算を遅くしないモードがある
MXCSRレジスタのDAZビット
Ax + b = 0, A=3x3行列 の連立方程式を解く関数を float(C++)からsse(C++ + 組み込み関数)へ移植したんだが 2倍程度遅い結果。これでも修正が効いた方で ベタ移植だと30倍ぐらい遅かった。 等速ならまだしも、何倍も遅くなる理由がわからん。 floatだって内部的にsse使ってるのに。 思うんだが、組み込み関数使うと コンパイラの最適化が相当オミットされてたりしないか?
そうだよ SSEを下手に使っても効果ないよ
そうなの? だったら、SSEとかAVXとか積まずに FPUをその分載せてくれた方が よっぽどマシだなぁ
上手に使えばいい話 なんでそういう思考になるの?アフォ?
>>350 だから上手に使った結果2倍遅いんだって。
SISDより遅いSIMDなんていらないじゃん普通。
>>351 単にSSEに置き換えても早くならないって書いたよね
基本だけどパイプラインとかアウトオブオーダーとか理解してる?
ていうかSSEの知識ないんだったら
>>347 の内容くらいBLASで解けばいいじゃん
>>352 何?組み込み関数を使うと
パイプラインがストールしたり、
インオーダー実行されちゃったりするの?
組み込み関数が遅いのはそんな理由じゃないよね。
つーか速くならないだけならいいんだってば。
現実は遅くなるの。それもとんでもなく。
floatだって、実際のコードはsseを使ってて
量的な差は無いはずなのにさ。
>>352 当然blasも使ってる。
ちなみにublasとubals相当の関数の比較だと
約5倍は遅い。
>>354 多少は知識あるじゃん
それでできないんだったらあきらめな
センスなさすぎw
検証比較ソース出せばすぐ検証して貰えるよ。
>>354 >コンパイラの最適化が相当オミットされてたりしないか?
これが正解
というか3x3だと最後の使わないデータがコンパイラには理解できないから
FPUはO(3x3)=O(9)
SSEはO(4x4)=O(16)
でコード次第では不利
つーか、こいつもしかしてintrinsicだと遅いっていってる? つまりアセンブラなら速いと こいつ性格悪そうだからそういう意味かもな
>>358 Ax + b = 0 は、3x4行列として扱う。
__m128 x 4本で無駄は出ない。
>>359 そうだよ。だってアセンブラは対象外だもん。
アセンブラで書くとコンパイラの最適化を阻害して
逆に遅くなるよ派だし。
intrinsicだと許せる理由の他に
許せない理由で遅くなってそうだと思って聞いてみたんだよ。
>__m128 x 4本で無駄は出ない。 __m128 x 3本の間違い
データの順番を変えられるなら、 1個ずつ連立方程式を解かず、 8個ずつず解けば速い。
あ、AVXじゃなくSSEか。 じゃあ4個ずつ。
>>360 >>アセンブラで書くとコンパイラの最適化を阻害して
>>逆に遅くなるよ派だし。
それはおまえの能力が低いからって言われるよ
ま、最適化より早いコード書くのは大変だけどね
時間かければ可能
構造体の並び順とか変数の参照回数とかは大抵コンパイラに任せた方が速い テーブル参照や三角行列化などのアルゴリズムに起因するものは人間が最適化しないといかん
割とテキトーに命令並べてもアウトオブオーダ実行でパイプライン埋めてくれるのでアセンブラで書くよ派 どのポートで実行されるかは意識して書くけどね
あれ、団子はintrinsic派じゃなかったっけ?
おいらはアセンブラ派。
もちろんどのポートで実行されるかとかレイテンシーとかは考慮する。
>>365 最近は構造体の並び順とかもコンパイラが勝手に並び変えるのか?
でも単純に並び変えてもほとんど恩恵が無いような。
SOAとAOSを最適化で切り替えてくれるならすごい恩恵はあるが、
まさかそんなところまで最適化は出来まい。
それは時と場合によって使い分ける intrinsicsは緩くかけるからいいんだよC++のinlineとかtemplateと相性いいしね 関数丸ごと最適化の場合はアセンブラ使うよ。 とりあえずMSはYMMレジスタ全てcaller-saveのABI規約作ってくれ
> それは時と場合によって使い分ける ふーん。 intrinsicマンセーぶりからしてアセンブラ使えないのかと思ってたよ。 > とりあえずMSはYMMレジスタ全てcaller-saveのABI規約作ってくれ これはその通り。 > intrinsicsは緩くかけるからいいんだよ そうだね。 AVXを使って緩くかけるような機会もそんなにないけど。
団子はこないだ intrinsics ディスってなかったか。 86 の事情は分からんが、ps3 で PPC VMX 向けなら、ひとまず intrinsics で書く。 ターゲットより規模の問題かもしれんけどね。
VCCだと64bitではintrinsicsしか使えないよね?
>>370 命令と1:1で対応している分逆にコンパイラの最適化が阻害されるケースがある
とかいったやつか?
所詮はintrinsicsは高級アセンブラだ。
コンパイラより賢いコードがかけるならそれでいいんだ。
アセンブラを使っても同じ。
intrinsicsと対比するなら、むしろコンパイラの自動ベクタライズ機能だ。
CilkとかCtとかまともに使えるならそっちでもいいんだけどな
「緩くかける」ってのはたとえば、SIMDレジスタ16本あっても変数が16以上ある場合なんかあるじゃん。
レジスタカラーリングは常に自分のほうがコンパイラより賢いとは限らない。
32ビットと64ビットで同じコードを使ったり、あるいは、ターゲットCPUごとにコンパイルオプションを変えて
命令スケジューリングをチューンしてみたりとか、そういう場合にある程度有効だと思う。
(32ビット+AVXってなるべく考えたくないな)
最終的にはサポートされてる命令ごとに同じ関数を何個も実装しないといけなくなって
頭がパーン(必須アモト酸が足りない)
AVXのコードは個人的にはYASMが一番書きやすいと思った。 凝り性だから2バイトVEXになるべく収まるように第2ソースオペランドに使う頻度の高い変数は ymm0-ymm7になるように配置したりとか、そういう試行錯誤もなかなか楽しい。 (当然%define使いまくり) 大きい関数になると流石に諦めたくなる。
AVXの命令を非対応のCPUに読み込ませたらどうなるんだ? 昔SSE2の整数命令をPen3で実行したらなぜか例外は全く起きず、MMXの相当する命令に置き換わったのか、 前半のエレメントだけ処理されたような形になった記憶があるが…。
自分でテストしてみりゃいいだろ
非対応CPUでも、非対応OS上の対応CPUでも例外発生
>>376 >>377 今あるのはVS2010とVistaとC2Qだけで、
>非対応CPUでも、非対応OS上の対応CPUでも例外発生
のとおりWin7SP1もCi7も持ってないので…。
結局Win7SP1上で走らせても相当するSSE命令に置き換わるようなことは無く、 処理単位だけ変えて同じ命令を使うようなことは出来ないと考えていい?
> 昔SSE2の整数命令をPen3で実行したらなぜか例外は全く起きず、MMXの相当する命令に置き換わったのか、 OSが例外を処理してたとか、 Pen3で中途半端にSSE2の実装がされていたとか、 .... AVXの場合はそんなことは無い。 潔くスパッと例外発生。 どちらも対応したければ、 XCR0レジスタでAVX対応かどうか判断して、 対応の場合と非対応の場合で別のコードを走らせる。
SSE2の、が勘違いだったんだろう
66, F3, F2=意図しないプリフィックスがついてるけど無視しちゃえ Athlon XPも同じ動きだね
あと、VC++なんかはSEH対応してるから、ためしにAVX命令を実行してみて 例外をキャッチしたら従来命令を実行って手も使えるけどな。
普通じゃなくてもしない。 と思ったが、流れ的にその場じゃなくてアプリケーションの先頭でそうやってチェックして、 以降切り替えるという意味なのかも知れないと思い直した。 でもしない。
>>385 じゃあどうかくの?
最初にcpuidで判別?
そうだね SIMD使うような性能重視のコードで、エミュレーショントラップなんてやってたら話にならないし 事前に切り分けるんだったら、例外なんか使う必要は普通ない
CPUIDだけじゃダメ。 XGETBVを使ってOSが対応しているかどうか調べる。
>>389 SIMD使うようなコードって、そもそも使うOSとか指定させないか?
そもそも未知のOSで動くバイナリなんて作れないでしょう。
将来のOSまでサポートできないしi7マシンにXP入れるようなバカも多いし XPをAVX対応にするようなやつも出てきそうだし あと今後はXPモードのような仮想環境も考える必要がありそうだし 結論 OS指定は無駄
現実的には、強制指定の手段をユーザーに提供して、一応自動検出するけれども ユーザー指定を優先して動作する、でいいんじゃないの?
エラッタ対策としてユーザーが無効化するのは十分にありかも
>>394 今見つかっていなくて、存在もしないかもしれない重度のエラッタが心配なら
AVXに限らずプログラムなんか組めないと思う。
ユーザーが速度をくらべてニヤニヤする為とかデバッグの為とかならわからないでもないが。
fdivみたいな計算結果が間違えるようなエラッタだったら選択方式とかありえんし どんなエラッタだと実行する命令を選択できることが嬉しいんだ
AVXのほうはどうよ? SSEより速くなった?
>>397 そりゃそうよ。ツボにはまれば倍に。
ベクトル化が難しいデータだと活用はSSE2より難しくなるけど。
ドット積のような計算やってみたんだが水平加算が数が増えた分遅くなるな とりあえずチューニングがむずい ちっともはやくならん
構造体の配列じゃなく、配列の構造体にする。 出来ないなら劇的な速度アップはムリ。
SOAかAOSとか言ってるレベルではないよ
データのベクトル化が無理なら劇的な速度アップはあきらめろ。
AVXは128ビットずれててもセグ違反にもならなず、しっかり計算してしまうぞ?
256bitアラインメントを要求するのは VMOVAPD VMOVAPS VMOVDQA VMOVNTDQ VMOVNTDQA VMOVNTPD VMOVNTPS
それって一切ペナルティ無しで?
ペンるてぃの有無は分からん 自分で確認してみてくれ
なんかSSEを2回やってるのと変わらん速度しかでないんだけど ほとんどの命令で倍近い時間がかかるのは仕様?
408 :
399 :2011/05/11(水) 20:46:30.30
同じく 今のところ対応不明 てか速くなるのかな?
そうか!
>>403 が言っている通りならAVX命令は本当にただのSSE命令2回分だ
少し納得
どんな処理でテストしてるの?
今は土台を作る時期
レジスタ同士の演算なら普通に倍の速度は出る。 メモリからのロードは(あんまりここがボトルネックにならないだろうから)工夫して凌ぐ。
floatの配列の合計を求めるプログラムで試してみたけど、 普通にAVXの方が半分の時間で済むぞ。 アラインメントをずらした実験だと、 128bit境界でないと極端に遅く、 128bit境界であれば256bit境界に無くても速い
まあロード・ストアは128なんだから不思議でもないんじゃない ただストアフォワーディングできるのは32Bアラインだけとかいう話だったような
416 :
399 :2011/05/14(土) 00:58:16.19
ドット積は水平加算が馬鹿になんないんだけどいい方法あるのかな? xmmレジスタに移動してシフトしたりしてるんだけど遅くて駄目だわ
>>415 整数命令はYMMを使えないが。
何に比べて何が2倍時間がかかると言ってるの?
>>416 水平演算がいらないようなデータ順にするのが一番。
とりあえず現状のコードを見せて。
419 :
399 :2011/05/14(土) 09:17:56.59
>>418 サンクス
イントリでこんな感じ(avxのアセンブラまだ覚えられんのね)
正確にはドット積というよりマトリクス・ベクトル積で4行同時に計算してる
for(j=0;j<m;j+=8)
{
__m256 mulA256 = _mm256_mul_ps(M[i+j], V[j]);
__m256 mulB256 = _mm256_mul_ps(M[i+1+j], V[j]);
__m256 mulC256 = _mm256_mul_ps(M[i+2+j], V[j]);
__m256 mulD256 = _mm256_mul_ps(M[i+3+j], V[j]);
sumA256 = _mm256_add_ps(sumA256, mulA256);
sumB256 = _mm256_add_ps(sumB256, mulB256);
sumC256 = _mm256_add_ps(sumC256, mulC256);
sumD256 = _mm256_add_ps(sumD256, mulD256);
}
→sum(A〜D)256の8つの数値をそれぞれ水平加算する
今はこれをsum256を_mm256_hadd_psとfloat*で二分割してxmmで水平加算してるが、ここで時間食っている
どうぞよろしくです
>>水平演算がいらないようなデータ順にするのが一番。
こんなことできるん?ベクトル演算しなけりゃ可能だろうけど…
avxならvdpps使えばいいんじゃね
>>419 なんかよくわからない
水平加算はループの外で行うの?
mが大きい値ならループの外の時間なんて誤差の範囲だから、
mはそんなに大きくない値?
だとするとさらに外側のループが存在する?
それならもうちょっと外側まで書いてほしいな。
> こんなことできるん?ベクトル演算しなけりゃ可能だろうけど… やりたい演算や、他のいろんな事情で可能かどうかが決まる。 たとえば5x5の行列と5次元ベクトルとの積をたくさん計算したい場合、 float m[5][5][N]; float v[5][N]; のような構造で持てれば速く計算できる。 でも、この並び順だと他の演算を行う時に都合がわるいとか作りにくいとかだったら 積の時間を犠牲にしてでもデータの並びを変えなくてはならない。 また、行列やベクトルの次元が固定でなければこの並びはちょっと無理がある。
今後SIMDのベクトル長が伸びれば さらにデータの並び順決めが重要になる。 AVXはせいぜい8個同時演算だが、 ベクトル計算機なんかだと1024個とかを同時に計算したりする。
>>422 その並びは水平加算は早いだろうけど他の計算量は全て増えちゃうね
ベクトル井演算の意味無くね?
井がなぜか紛れ込んだ 無視して
>>424 どういうコードを想定してる?
ベクトル化がわかってないでしょ。
5x5の行列と5次元ベクトルとの積を普通にやると、
計算量は、乗算25回、加算20回。
_mm256_mul_ps を25回、_mm256_add_ps を20回 で
行列とベクトルの積を8個行うんだよ。
SIMDを用いた計算へののアプローチは2種類あって、
ひとつは
>>426 のように、SIMDの要素分データを並列に並べ、並列計算を行う方法。
std::valarrayみたいなもんだと思えばいい。
もうひとつはデータの並列化はせずに、行列の行や列をSIMDレジスタにそのままマップして計算する方法。
D3DXMATRIXのSSE対応とかがそう。
>>419 もそうかな。
基本的に前者はデータの配置に制限を持つが、無駄がなく効率が良い。
後者はデータの配置に制限は無いが、効率が悪い。
float m[5][5][N];のNは空にするんじゃなくてデータ入れるのか なるほど意味理解した で、あれば速いね
同じ人かどうかは知らないけど
>>401 みたいに書いてるから
当然ベクトル化の意味がわかってると思ったんだけど
わかってなかったのね
430 :
399 :2011/05/14(土) 23:19:55.51
水平加算を避けるのは行列の転置ができればいいってことだね 生憎、それは無理 単純なドット積も他にあるしSSE2とAVXで使い分けするしかないかなぁ
>>431 それ位のインセンティブが無いと移行する気が起きないな。
もうAVX2の話でてんのか 今くらいのタイミングで出るってことは、IvyBridgeに搭載される可能性高そうだな
整数演算が256ビット化するならIvyBridgeはCore2並に長く付き合える良作になりそうだな
Ivyは単にシュリンクだけ じゃなかった?
いくらか手を入れるとかニュースでみたような。
437 :
デフォルトの名無しさん :2011/06/25(土) 22:51:57.56
Iacaでコード解析したときのperformance latencyって解析範囲を実行するときにかかると思われるサイクル数と理解すれば良いの?
あんまり参考になんないんだよね
AVX2はhaswellかぁ IvyBridgeなら買ったのに ところで、SandyのAVXって、Core以前のSSEみたいに、 128bitユニット2個使って演算、みたいなことやってるん?
やってないよ。AVX使えば性能倍になる。Bulldozerは128bitx2。
AVX1の整数は128bitのままでしょ。 3オペランド化によるレジスタ割付の改善やコピーの削減による効果はあるだろうけど、 SSE2が登場して、Pen3が急速に時代遅れになっていったのと同じリスク抱えた 代物だと思ってる。
AVX1は浮動小数点の256bit化が売り。あとはオマケ。 パフォーマンスは256bitの加減算と乗算を同時に1クロックで出来る。 CORE以前のSSEとは異なる。 AVX2は整数命令の256bit化。
Pen3からCore2までかかってようやく完成したSSEに比べると Sandyから次のtockのHaswellで完成するAVXは驚異的なハイペースだな
整数で16並列とか32並列とかプログラマとしては嬉しくないんだけど・・・ SSEでさえ8ビット演算はロードとストアが面倒だし、下手すると遅くなるし・・・ SSEだと特にSSE2の16ビット整数が便利だったからAVXは32ビット整数がメインかな? と思ったけど今後も一番重いのは画像処理だろうし、画像で32ビットって何に使うんだ? 結局AVXは流行るのか?
447 :
441 :2011/08/04(木) 00:06:30.41
>442 ごめんちゃんと調べずに書いてたわ。 - 内部は 128bitx2 になっているが、パイプはFADD/FMULで一本ずつしかないので128bit演算のスループットが倍になっているわけではない(Core以前のSSEとは違う) - ロードは256bitを128bitx2で使える。なのでスカラのロードもスループット倍になっている だった。 まあ、256bit浮動小数演算を繰り返すだけなら、256bitのパイプがADDとMULで一本づつある、という理解でいいと思うけど。
AVXは32bit/64bitの浮動小数点がメイン。 画像も音声も途中の処理は今後どんどん浮動小数点化していく。
しかし主流の肝心のH.264は浮動小数点を使えない、というか使わない設計になっている。 今のところAVXの出番は無いかもしれん。
その辺はAVX2まで待ちかな
低レベルな質問で申し訳ないんですが、x64からインラインアセンブラ が使えなくなっているのに気づいたのですが、これってどんな理由が あってのことなんでしょうか? インラインアセンブラとintrinsicのメリット・デメリット的なものを知りたいです。
vc2010限定の話だろ
>>451 理由としてはこんな感じだろうか・・・
・Windowsのx64ソフトウェア呼び出し規約は面倒だからプログラマがミスし易い
・関数のプロローグ/エピローグを指定する新たなキーワードとか作りたくない
・リーフ関数なら楽に作れるけど大した事出来ないからintrinsicで良いんじゃね?
・何で動かないの?とか言ってくる奴のサポートしたくない
nasm使い始めた頃、自動でxdata,pdataを作るマクロ組んだけどクソ面倒だったわ
.xdata、.pdataはNASMの問題だろ第一インラインasmじゃねーし
インラインにすると前後のCコードから生成されるアセンブラを整合性が 取れる形にしなきゃいけないからコンパイラを作る上で大きな足枷になる。 それに最近のコンパイラはかなり優秀だし、どうしても使いたいなら インラインじゃないアセンブラを別途コンパイルしてリンクすればいい。
そもそも、intrinsic ってすべてのアセンブラ命令に対して用意されてないよね? インライン廃止して置き換えきくものなの?
ML64をどうぞ
Intelコンパイラでは64ビットでも使える
Intelコンパイラは普通に使えるから問題ないんだけど、 常にIntelコンパイラが使えるとは限らないからねぇ。 今は無理してインラインアセンブラで書かなくとも、 Intrinsicを使ってもそんなにさがない場合が多いし、 汎用性を考えると殆どIntrinsicを使うようになってしもうた。
YASMでいいやって思うようになった
461 :
デフォルトの名無しさん :2011/09/05(月) 00:49:29.68
変数一個とSIMD用のレジスタ直接演算できないの?
不自由でない日本語でおk
32bitレジスタの内容とxmmレジスタの4領域の内容で四則演算したい。 四則演算が無理でも、xmmレジスタの4領域を一命令で全て同一の値にできたらありがたい。
それって _mm_set1_epi32() とかじゃダメなわけ?
>>465 まさしくそれです。
ありがとうございます。
_mm_set1_epi32ってgccで使ったらめちゃくちゃアホなコード吐いてた記憶がある
gccがアホなだけでは?
だからそう言いたいってことだろ アホか?
_mm_set1_epi32はアホなコードが吐き出される可能性があるからダメだ、という風にもとれるが。
>>469 はちょっと頭が悪すぎるんじゃなかろうか。
お前がアホだw
アホなコードが吐き出される可能性があるのはintrinsics全部だろ…
お前ほどじゃない。
475 :
デフォルトの名無しさん :2011/10/17(月) 16:33:18.43
コンパイラによる最適化前提で、こんなのとか。 #include <smmintrin.h> double NormalizeDouble(double value, register int digits){ static double t0[] = {1, 10, 100, 1000, 10000, 100000}; static double t1[] = { 1, 0.1, 0.01, 0.001, 0.0001, 0.00001 }; __m128d xmm0 = _mm_set_sd(value); __m128d xmm1 = _mm_set_sd(t0[digits]); __m128d xmm2 = _mm_set_sd(t1[digits]); xmm0 = _mm_mul_sd(xmm0, xmm1); xmm0 = _mm_round_pd(xmm0, 0); //ほぼ四捨五入。こまけぇこたぁいいんだよ! xmm0 = _mm_mul_sd(xmm0, xmm2); return _mm_cvtsd_f64(xmm0); } うん、多分早くなってない。
>>476 おぉ、サンクス!
3割くらい速くなってるぽい。
ちなみにg++ -O -msse4.1の結果: __Z18NormalizeDoubleSSEdi: pushl %ebp movl %esp, %ebp subl $8, %esp movl 16(%ebp), %eax movsd 8(%ebp), %xmm0 movsd __ZZ18NormalizeDoubleSSEdiE2t0(,%eax,8), %xmm1 mulsd %xmm1, %xmm0 roundpd $0, %xmm0, %xmm0 movsd __ZZ18NormalizeDoubleSSEdiE2t1(,%eax,8), %xmm1 mulsd %xmm1, %xmm0 movlpd %xmm0, -8(%ebp) fldl -8(%ebp) leave ret
お、-msseregparmつけたらさらに3割くらい速くなったっぽ。 ググってもこの手の話題出ないね。
まさかと思うが、-msseregparmで検索してないだろうな。
したけど何か? 6500件、日本語ページ8件とか。
先頭にハイフンがついていると否定検索になるって言いたいんじゃないだろか。
まさか"-"つきで検索できないバカでもないだろうに、なんだろうね。
メモリ上のテーブル参照するのと、SSE使って逆数求めるのでは、どっちが早いんだろうか?
だめだ、-msseregparmつけると単体テストじゃ動くのにどっかおかしくなるな...
名前からするとそのオプションってABIを変更するんじゃないか? だとしたらリンクする全てのプログラムをそのオプションでリコンパイルしないとダメとか?
manにはそう書いてあるしもちろんそうしてるがダメなんだよ。
libcも
>>488 そうやね、今man読み直して理解した。
attribute()使ってみるわ。
● -mregparm=num regparm属性により,コンパイラは最高でnumberによって指定される個数までの整数引き数を, スタックではなくEAX,EDX,ECXレジスタに入れて渡すようになります. # gcc test238.c -S # gcc test238.c -mregparm=3 -S スタックで渡す方法で生成されたアセンブラをリスト4に, レジスタで渡すように生成されたアセンブラを リスト5に示します.また,元のソースをリスト6に示します. 引き数がレジスタに渡されていることがわかります.
491 :
デフォルトの名無しさん :2011/10/28(金) 23:41:12.75
/* 質問させて下さい。ゼロかどうかを判断するにはどうすればよいか悩んでいます。 現在は、下のようにプログラムを組んでいますが、特に SSE2 の場合遅いです。 実際のプログラムでは表示ではなく、if 文の条件式の中で使っています。 CPU は Core2Duo E6600 と Core2Quad Q9550 です。どなたか教えてください。*/ #include <smmintrin.h> #include <stdio.h> typedef union tagMM { long long i[2]; __m128i m; } mm_t; const mm_t MM_FULL = {{-1,-1}}; #define IS_ZERO_SSE4(A) (_mm_testz_si128(A,MM_FULL.m)!=0) int IS_ZERO_SSE2(const __m128i a) { long long temp[2]; _mm_storeu_si128((__m128i*)temp,a); return temp[0]==0&&temp[1]==0; } int main(void) { mm_t zero={{0,0}}, test={{0,8}}; printf("zero SSE2:%d SSE4:%d\n",IS_ZERO_SSE2(zero.m),IS_ZERO_SSE4(zero.m)); printf("test SSE2:%d SSE4:%d\n",IS_ZERO_SSE2(test.m),IS_ZERO_SSE4(test.m)); return 0; }
なんか知らんがSSEで0比較程度のものをやるだけなら遅くて当然だと思うが
メンバにm128i_i64を持ってる処理系ならそれ使ったほうが見やすい
こんなのでいいんじゃね? int IS_ZERO_SSE2(const __m128i a) { return _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_setzero_si128(),a)) == 0xffff; }
495 :
491 :2011/10/29(土) 01:44:32.89
>>494 素晴らしい! ありがとう。
これは思いつかなかった。
>>491 stackに積んであるのを積み直すとか、アリエナイ。
return 0 == (a.m128i_u32[0]| a.m128i_u32[1]| a.m128i_u32[2]| a.m128i_u32[3]);
497 :
デフォルトの名無しさん :2011/11/02(水) 23:39:21.83
初心者ですがこれ読んどけって書籍ありますか? あまり情報が無いので
団子の書き込み
インテルの資料だけで充分以上に思えるが…
なんか書籍にするようなもんじゃないって気がするな
Intel C++コンパイラー・ユーザー・リファレンス・ガイドの組み込み関数リファレンス部分にはだいぶお世話になってる。 これと、Intelが配布してるIA-32アーキテクチャマニュアルだけで困ったことは殆ど無い。 組み込み関数使う派だけど、あんまり頭の性能よくないから、アンチョコ無しでは書けないんだよね、俺。 すぐに「SSE2までだとどんな命令あったっけ?」「うろ覚えだけどこんな感じのあったよね?」ってな感じになる。 使ってなんとなく覚える→忘れるを繰り返す感じ。 猿でも使えるSIMDアルゴリズムコピペ事典とか誰か作らないかな。 DVD-ROM付きで、やりたいことを検索すると、サンプルコードとアルゴリズムの解説が出てくるようなやつ。
503 :
デフォルトの名無しさん :2011/11/04(金) 01:19:54.70
>>502 おっ?そんなもの作ってくれるのか
よろしく
ここで作る?
SSEで投機計算するのに向いてる分野ってある?
GPGPUが登場して以降、CPUで計算するような分野じゃなくなりつつあるから…>並列処理 ここで話すようなことではないけれど、同様のものならGPU利用のものやシェーダーのそれのほうが 需要が多そうな気もする。
GPGPU?縛りきつくて使い物にならないからいらね。
...なんてこった、日本語がないじゃないか。
あー、でも検索しやすい。いいねこれ。 ありがとう!
簡単な関数ならYASMで書いちゃうのも手かな。 OSごとのレジスタ渡しの違い考慮するのがめんどいけど。
机の横に置くなら本よりもPDFが読めるタブレットだな。
書き込みできねぇし それにしても二つのRGB値を混合する命令くらい載せろよ電卓野郎
ペンタブでpdfに書き込みまくれるようにならんの?
PCならふつーに出来る。
GALAPAGOSのXDMF形式なら各ページ200文字程度までメモは残せる。 PC側のクライアントで変換できるんじゃなかったかな。 GALAPAGOSどこにも売ってねえ
ymmレジスタでメモリコピー書いてみたんだが、速度がSSEとほとんどかわらん。 基本的に同じ程度しかパフォーマンスが出ない認識でおk?
storeが16バイト/clkなので、単純なメモリコピーじゃ性能出ないよ。 レジスタ上で何かしらオペレーションするコードでないとSSEとの差を出しにくい。
将来的に速くなることはないかな?
キャッシュ内ならあるかもね
HaswellでL1帯域を2倍にするって噂だな 相対的にコストの高い外部メモリ帯域は諦めてでも チップ内帯域と生FLOPSを上げた方が全体でパフォーマンスを出せる というのがここしばらくの流れだよね NECのベクトルスパコンですらB/F比を下げ続けてるから
冬休みにSandy-EをIYHしたので、浮かれた気分でSSEで書かれた自前のコードをAVXに頑張って書き換えてみた。 2倍まで行かなくてもせめて2割くらいは。。。と思っていたら全く変わらなかった。 アセンブリを見てみると、アライメントがとれているのにvmovupsを使っていたので、 組み込み関数が悪いのかと思い、頑張ってインラインアセンブラで書き換えてみた。 結果は変わらないどころか、少し遅くなってしまった。。。orz アライメントがとれていれば、vmovupsを使ってもvmovapsをつかっても変わらんのか? ちなみにインテルコンパイラを使って試した限り。 GCCでは組み込み関数は使えたけど、インラインアセンブラではymmレジスタが使えんかった。
>アライメントがとれていれば、vmovupsを使ってもvmovapsをつかっても変わらんのか? 変わらない AVX256化して速くならないとすると store幅は変わってないとか insertf128でport5ボトルネックとか フロントエンドボトルネックでuOPキャッシュに入る程度にループを小さくする必要があるとか AVX256ってなんかデコーダにペナルティある気がするんだけど気のせい?
AVXは128bitでもmovapsがいらないからport5が空くのとレイテンシが短くなるのとで速くなることが多いけどね -xAVXで全く変わらないんであればそもそもなんか別のところがボトルネックな気がする
現状のAVXは命令数が減ってちょっと速くなる事がある程度。 AVX2が来ないうちは色々楽しめない。来てもたいして速くならないかもしれない。 コア増えてくれたほうが、普通にリニアに速くなってくれる。
わけでもない。
単純にメモリネックだったりしない?
>>527 FPUの演算ボトルネックならSandyBridgeのAVX256bit化で2倍近くになるだろ
GEMMとかね
SandyBridgeのAVXはデータパスは既存を流用して演算器だけの追加だから
Westmereと比較するとかなり少ない追加コスト済んでいる
>AVX2が来ないうちは色々楽しめない。
と言っているようなFMAが有効なプログラムではコア増やすより安上がり
FMAが有効なような演算ボトルネックのプログラムなら 言葉足らずだったすまん
現行AVXではシャッフルがあんまり自由利かないからね。 ループの内側でvinsert*/vextractを繰り返してるようならデータ構造そのものを 変える(AoS-SoA変換して)方が効率あがることもあるよ。 メモリにボトルネックはないって自信があるならIACAで静的コード解析してみるのも手だと思うよ。
AVXはvbroadcastもソースがメモリオペランドに限定されていたり使いにくいよね IACAはバイパスレイテンシが入ってないとか あんまり精度の良いツールではないよな もっとましなパイプラインシミュレータを公開すればいいと思うんだけどね Intelの開発現場では確実に使っているはずなんだから
>>524 > GCCでは組み込み関数は使えたけど、インラインアセンブラではymmレジスタが使えんかった。
GCC 4.5.2で出るけど?
__m256 v0, v1, v2;
asm volatile ("vaddps %2, %1, %0\n\t":"=x"(v0):"x"(v1), "x"(v2));
俺もAVXに対応したけど全く変わらないな ベクトルのdot演算とかユークリッドノルムとか超基本的な処理なんだが
だーかーらー
内積はデータ量も演算量もNに比例するからメモリ帯域ボトルネックだろ 行列積が速くなるのはデータ量はN^2演算量はN^3なのでキャッシュが有効だから
538 :
524 :2012/01/07(土) 00:02:40.65
色々と調べてみたら、どうもメモリがボトルネックだったようで、
6スレッドではなく、1スレッドで動かせばAVXを使うと1割くらい早くなった。
でも6スレッド走らせると、SSEより若干遅くなった。
>>534 直接ymm0とか書きこむとエラーはいて止まってしまった。
539 :
534 :2012/01/07(土) 14:39:47.14
>>538 手元だと出るけど?
入出力オペランド付けるときは%%ymm0、付けないときは%ymm0とか、そういうのを間違ってる気がする。
何だ初心者かよ
>>539 こんな感じでコンパイルかけると、
asm volatile (
"vmovups (%2), %%ymm0\n\t"
"vmovups (%3), %%ymm1\n\t"
"vmovups (%4), %%ymm2\n\t"
処理が続く
)
こんなエラーを吐く。
xxx.cpp:xxx:x:不明なレジスタ名 ‘%ymm1’ が ‘asm’ 内にあります
とかが続く。
xmmは問題なし。
インテルコンパイラだと問題ないからあんまり気にしていない。
ちなみにUbuntu11.10でGCC4.6.1でも4.4.6でもおんなじだった。
>>540 団子さんに比べたら初心者かもね。
団子さん、Intelに転職してアーキテクトやってくれよ。
gcc -v
Ubuntu11.10でgcc4.6.1でも4.4.6でも普通に通るけどな バージョンはbinutilsの方が重要な気はするけど
545 :
541 :2012/01/09(月) 11:04:46.90
>>544 binutilsはbinutils 2.21.53.20110810-0ubuntu5.1。
まあ、自分のシステムが変な設定しているのかも。
レスサンクス。
>>541 単にAVX用のオプション指定してコンパイルしてないとか?
本当にbinutilsが関係してるのかなぁ…
インラインアセンブラの意味解析をasに丸投げはしてないでしょ。
__m256な変数とレジスタの対応付けをしなけりゃそのままアセンブリに挿入されるだけだよ %%ymm20とか存在しないレジスタを含んだコードもコンパイルまでは通るのがその証拠 だからAVXに対応していないバージョンのgccでもインラインアセンブラでAVXを使って yasmでアセンブルするとかも可能
MacPortsだったらbinutilsがAVXに対応してないのでclang使え
>>541 破壊オペランド(asmの最後のオペランド)にymmって書くとそのエラーになるみたい。
ymmのかわりにxmm書いとけば大丈夫な挙動をしてるように見えるが、どうなんだろう…
バージョンと環境とシンプルな検証コードをコピペするところはじめたら
>>547 >__m256な変数とレジスタの対応付けをしなけりゃそのままアセンブリに挿入されるだけだよ
>%%ymm20とか存在しないレジスタを含んだコードもコンパイルまでは通るのがその証拠
ええ、そうなんだ。知らなかった。
結構いい加減なのね。
ymm20ワロタ
どうマッピングされるの?
誰か同じ内容の処理をSIMDでやると消費電力が減るとか、電力当たりの処理量が上がるとか、その手の話って知らない?
GPGPU絡みの論文でも漁ってみたら
よく知らないけど、さっさと仕事終わらせてHALTかければ時間あたりのWattすうへるんじゃね?
よく知らないけど命令数減るんだから電力減るんじゃね?
AVX2でunsignedな比較ぐらい用意しとけよIntel
Javaにはunsignedなんてないぜ
たぶんAMDが用意してくれるよ
またかよ
563 :
デフォルトの名無しさん :2012/05/11(金) 23:53:38.33
ちゃんと__declspec(align(16))を付けているんだけど __m128メンバが16バイト境界に置かれずアクセス違反で落ちる 生成場所はヒープじゃなくてスタックだし・・ VC++2010EEfだけど打つ手なし?どーすりゃいいんだろ?
と思ったらヒープだったみたい お騒がせしたし
>>563 構造体の宣言と変数の定義両方につけてる?
>>565 いや、__m128メンバを持つクラスを持つ
もっと底のインスタンスがヒープでした。
そいつは_aligned_mallocで確保してなかった。
つーか対応すんの超面倒
placement new書けばよろし てか、__m128は計算時に使うものでメンバに持たないほうがいいのでは どちらにしろデータのアライメントはいるけども
operator newはどこまで遡って付ける羽目になるかわからんし std::vectorにはallocator無しじゃ入れられないし わかってりゃそもそも使わなかった・・
32bitを使っていると8バイトでアライメントされるから、 64bit使えばいいんじゃない。 まあ、AVXではおんなじことが起こるけど。 そんときは128bitのOSで・・・・。
__m65536をアライメントするには一体何ビットのOSが必要なんだ
16[bit(s)]で十分。 vectorに突っ込む発想は無かった。
Ivy BridgeでAVXは拡張されてるのでしょうか?
されません
574 :
デフォルトの名無しさん :2012/05/24(木) 23:41:14.54
やっぱりヒープの_aligned_mallocが納得出来ない。 例えば、以下のクラスがあったとすると、 class A{ char x; __m128 y; }; A* a = new A; // NG A* a = new( _aligned_malloc(16) ) A; // OK
575 :
デフォルトの名無しさん :2012/05/24(木) 23:41:50.10
16byte境界にアラインしなきゃいけないのはAのインスタンスじゃなくて Aのインスタンスのメンバのyのはずだよね? なんで、Aをnewするのに16byte境界にそろえなきゃいけないの?
class A { void *p; } ってあって、4バイトアラインが必要なのはAじゃなくてA::pだよね? なんでAをnewするのに…っておかしくね?
if (__alignof(T) > 8) {... みたいな分岐を見てしまった時の絶望感
>>574 yを__declspec(align(16))とか__attribute__((aligned(16)))でアライメント指定したうえで
(__m128はそのように定義済み)
A自体も_aligned_mallocしないと
Aの先頭アドレス*A内におけるyの先頭アドレスが16の倍数になる保証がないのでは
そういう境界は、コンパイラなりライブラリ内で
>>577 みたいにしていて気にしなくても良さそうなものだけど。
>>574 >>575 基本的にnewはアライメント属性を無視しランタイム固有のアライメントでアドレスを返してくるので使えない。
メンバ変数のアライメントを合わせるには
A *a = new(_aligned_offset_malloc(sizeof(A), 16, offsetof(A, y))) A; // offsetofはmalloc.h
を使うが、
__m128はアライメント属性 __declspec(align(16)) を持っているので
class A {
char x;
char pad[15]; // <--- 変数としては見えないけど存在する
__m128 y;
};
となり、Aのインスタンスの先頭を16バイトアライメントすれば自動的にA::yのアライメントも合う様になっている。
なのでより引数の少ない
A *a = new(_aligned_malloc(sizeof(A), 16)) A;
でOK。
なんで納得できないのか理解できねーよな sizeof(A)が動的に変化するとでも思ってんのかねぇ
メンバーのアライメントの指定がクラス内や構造体内でのアライメントの指定であって クラスや構造体の先頭アドレスが指定したアライメントの倍数でなければ メンバのメモリアドレスがアライメントの倍数になるわけではない ってことが分かってないだけだろ
構造体のアライメントは正しく16になるけどoperator newが16バイトにアラインしてくれない問題なんだけど、 構造体のアライメントが16にならない問題だと誤解されている気がする。
VirtualAlloc使えよ アラインメントがページサイズの4096バイトになるから
operator newが16バイトにアラインしてくれないなら 構造体のアライメントは正しく16になってないだろ
生メモリ (N+1)*sizeof(T)バイト取ってstd::alignでも使ってろよ
>585 __alignof で見てみなって。16になってるから。 VCのoperator newが単にmallocするだけで、mallocが8でしかalignしないのが問題だよ。 > If arg >= 8, alignment will be 8 byte aligned. If arg < 8, alignment will be the first power of 2 less than arg.
どうもクラスでアライメントって抵抗あるなあ。 どうしても構造体にしてしまうわ。
構造体にしてクラスメンバに持たせたら同じことが起こる
class A{ char x; __m128 y; public: void *operator new(size_t size) {return _aligned_malloc(size, 16);} void *operator new[](size_t size) {return _aligned_malloc(size, 16);} void operator delete(void *p) {_aligned_free(p);} void operator delete[](void *p) {_aligned_free(p);} };
_mm_mallocの方が移植性高いぞ
>>591 _mm_mallocはでかい領域のメモリ確保に失敗することがあるから、
newで作れるならnewの方がいい。
確保の速度を気にしないのなら自分でアロケータを作るのがいいと思うが。
なんか知らんが、適当に確保したあとアライメントと調整するのが普通だろ。
まともなOSならposix_memalign()使えるから。
>>594 Windowsはまともじゃないんだな。
Linuxではposix_memalign()でも数十GBのメモリ確保は出来なかったな。
OSのメモリ管理によるのだろうけど。
昔書いたaligned_mallocを見たら、size+alignのoverflowを考慮していなかった。 /(^o^)\
>>595 今時posixも満足にサポートしないのはまともなOSじゃないでしょ。
OSXではposix_memalign()で100TBとか普通に確保できる。実メモリは当然mapされてないけど。
あとOSXやiOSのmalloc()/newはちゃんと16 byte alignされた領域を返す。
posix信者キモい
僕のちん○もposix準拠です
>>597 Linuxだと、_mm_mallocやposix_memalign()だと、大体搭載メモリの半分ぐらいで確保を諦めたみたいでエラーで落ちていたな。デバッグがかなり大変だった記憶しか無い。今は知らいないが。
> 今時posixも満足にサポートしないのはまともなOSじゃないでしょ。
> OSXではposix_memalign()で100TBとか普通に確保できる。実メモリは当然mapされてないけど。
確保されてねーじゃんwww。
>>600 >確保されてねーじゃんwww。
仮想記憶下のメモリアロケーションとはそういう物だよ。
実メモリがmapされるのは確保したページに最初に触った時。
ファイルをmmapした時も同様、触った所だけメモリ上に現れる。
>>601 ん?
>>601 のPCに100TBのストレージがあるとは思えないし、100TBは仮想メモリのどこに確保されたの?
アクセスの途中でエラーにでもなるのか?
手抜きなOSはアクセスされて初めて実メモリを確保する。 Linuxのmanpageにも "This is a really bad bug." って書いてあるし、POSIX以前にCとしておかしい。
オーバーコミットも知らないアホがいんのかよ
OOM Killer先輩オッスオッス
>>603 Linuxもdemand paging使ってるから、触ったら実メモリ確保だよ。
アドレス空間確保と実メモリ確保の関係解ってない奴は仮想記憶の
基礎から学んでくれ。
急に例外が来たので。
メモリがwrittenになることはできませんでした!
linux64bit, java7u4(32bit), jni(gcc4.6 -m32)で、javaからsseは有用かどうかベンチマークなどを作りながら数日調査してるんですが、sseの成績はまったくかんばしくありません。 少なくともループでA[k]+=B[k]やA[k]=A[k]*B[k]+C[k]など単純なものはsseはjava forloopの2倍以上遅くなります。(2000回ループなどではsseが2,3倍速いときもあります。) jniのスタックコールが足を引っ張るのは分かるのですが、それがsseが歌うfloatを4つ一度にopするので高速を打ち消すほどでなんですか? MAC(FMA)はsse1,sse2にないのでaddps,mulpsで作ってますが、基本的にfloat,intしか興味ないのでapiとしてはsse1の範囲です。
float4の演算4回よりメモリアクセスの方が遙かにコスト高くね?
Javaはよく知らんが、floatとdoubleの変換は発生してたりしないよね。 どの途、4倍にはならないと思う。3倍行ってりゃ御の字じゃね?
jvmに限らず、asm,c99などネイティブオブジェクト生成環境以外からsseをコールするとなると関数呼び出し呼び戻しのスタックコールのコストが問題になるので、vmからsseは有用か否かの問題java(jni)だけの問題じゃないと思うんですけど。 たとえばjvmに限らず、rubyなどscript vmや、browser組み込みのjs runtimeもsseはまったく使えないということです。 OpenCL, Open64, OpenMPの方でやろうと思うのですが、sse,avxはx86ネイティブ環境以外もうオワコンなんですか?
よく知らんけどループごとCで書けば関数呼び出しは1回で済むんじゃないの
使い方間違ってるのにオワコンとか言われてもお前ん中ではそうなんだろとしか言いようないわ
間違ってるかどうかこれだけの情報ではわからんよ ちょっとググってみてもJNIのコストは非常に大きいという愚痴が多数見つかるからな ま、Javaがオワコンということでここはひとつ
vmやnative環境に関係なく、ベンチ作ってテストをしていて気がついたんですけど、 floatが4程度だと配列添字のアドレッシング計算のためにx[offset+k+3]でsseの一度に4つ演算は相殺になりませんか? for (k=0; k<N; k+=4) { float a[]={x[k],x[k+1],x[k+2],x[k+3]} float b[]={y[k],y[k+1],y[k+2],y[k+3]} v4sf ssea=__builtin_load(a), sseb=__builtin_load(a); ssea=__builtin_add(ssea, sseb); __builtin_store(ret,ssea); } 単純なコードはこのようなものですが、add(ssea,sseb)を計算するために、offset+k+3 などをメモリスタックx,yからsseレジスタへ転送するために8回+しているので、sse_addの効果がまったくなくなるようです。 またmovups(x+offset+k)だとしても、sse_addを使えば4回の + が一回で済むように見えますが、実際は x+offset+k, y+offset+k でvoid* typeの + を2回してるので、これも(メモリアクセス遅延の問題以外に)sseが永遠に越えられない壁として問題あるように思います。 メモリアクセスについては、movntps, movaps (loadaps)などアラインメントに神経質になってもそれに見合う性能向上はまったくないのでmovupsしか興味ありません。
なんでスタックにコピーしてるの?
for (k=0; k<LENGTH; k+=4) { float arra[]={x[offset+k],x[offset+k+1],x[offset+k+2],x[offset+k+3]}; float arrb[]={y[offset+k],y[offset+k+1],y[offset+k+2],y[offset+k+3]}; v4sf ssea=__builtin_load(arra), sseb=__builtin_load(arra); ssea=__builtin_add(ssea, sseb); __builtin_store(ret+offset+k,ssea); }
for (k=0; k<LENGTH; k+=4) { float arra[]={x[offset+k],x[offset+k+1],x[offset+k+2],x[offset+k+3]}; float arrb[]={y[offset+k],y[offset+k+1],y[offset+k+2],y[offset+k+3]}; v4sf ssea=__builtin_load(arra); v4sf sseb=__builtin_load(arrb); ssea=__builtin_add(ssea, sseb); __builtin_store(ret+offset+k,ssea); } for (k=0; k<LENGTH; k+=4) { v4sf ssea=__builtin_load(x+offset+k); v4sf sseb=__builtin_load(y+offset+k); ssea=__builtin_add(ssea, sseb); __builtin_store(ret+offset+k,ssea); } float[]で受けるかv4sfで直接初期化するは、本質的に有意な差はありません(多分)。 それよりもv4sf ssea[], *ssebなどのようなデータのブロックについて、 ret+offset+k などでアドレッシングを求めるために + が数回必要なのはsse apiをいくら拡張しても回避できません。 sse,avxはアラインメントも含めて非常に神経質であり、あまり深入りしてもsse,avx設計思想ではx86上のvm(java, dotnet, js, scriptlang)ですら性能向上は全くなく、 時間を使ってsse,avxを勉強してもそれに見合うプログラムの性能向上もないのでほかのストリーミング演算開発環境を検証します。
あー、どうしようもなく間違ってたな 多分君は生粋のJAVAerで、ポインタを知らないんだよね
java使ってる時点で速度云々言うのはおかしいと思う
俺もそう思う
4 floatのときはsseの性能向上はもとの[]ループのコードと比べて、a,b,retのために3回整数アドレス計算する必要があるから4/3=1.33 倍 (3/4 * 100%)が限界なんだろうな。
>float a[]={x[k],x[k+1],x[k+2],x[k+3]} これはひどい。
626 :
デフォルトの名無しさん :2012/06/05(火) 19:38:05.94
x,y,retがfloat*なら x+= offset; y+= offset; ret += offset; for (k=0; k<LENGTH; k+=4, x+=4,y+=4,ret+=4) { v4sf ssea=__builtin_load(x); v4sf sseb=__builtin_load(y); ssea=__builtin_add(ssea, sseb); __builtin_store(ret,ssea); } でいいだろ
もしあなたが速度狂・最適化狂を自称するなら、ポインタ変数は変更不能の方がいいですよ 例えば float *const, float *restrict など
628 :
デフォルトの名無しさん :2012/06/06(水) 05:46:51.35
>>627 もしあなたが速度狂・最適化狂を自称するなら
比較コード書いてベンチマークで示してみ
できないから
>>620 なんかうまく言えないが、ひどいコードだな。
>>628 何がどうできない?
もしあなたが(ry
ちゃんと説明くらい書かんと。
A V X ってなんかエロいな・・・
>>631 AVがAudio&VisualではなくAdultVideoだと思う口かw
>>632 あの呼称、やめてほしいよね。
「趣味はAVです」って言えないw
ピュアヲタなんて恥ずかしいもんな
Javaスレじゃないから多くは書かないが、 Javaから大きい配列をMappedByteBuufer 以外の方法でJNI+C/C++に渡してたりしないか? だったら遅くなるだろうし。 そもそも、JNI+C/C++側で「なにもせずに」値を返すだけのプログラムを書いてもJNIのせいで 遅かったりしないか? (だったら、SSE/AVXはおろか、OpenCL/CUDA/DirectCompute も当然遅いわけだが)
どうしてMappedByteBuuferなんですか?
PREFETCHはキャッシュレベル指定できる別命令があるから要らないでしょ だが正直今更だな
639 :
デフォルトの名無しさん :2012/09/21(金) 01:05:42.45
なんか忘れ去られたスレだな。 とりあえず、__m128とか__m256になってもいまだにシフトをleftとかrightとかで呼んでんじゃねーよ。 頭ん中じゃハイアドレスが右だからわかりにくいんだよ。
VEX encodedな命令はm128とかm256をオペランドに取れる演算命令で メモリのアラインメントを気にしなくて良くなったことに今更気付いた AMDはK10あたりで独自拡張してたようだが
641 :
デフォルトの名無しさん :2012/09/21(金) 09:49:34.17
SSE2やAVXって 倍精度使えるようになっても 除算や平方根の精度って11bitのまま? やっぱり倍精度なんだから5xbitまで、精度を求めるべき? またそれは現実的に可能か?
rsqrt*/rcp*のことならもともと単精度しかサポートしてない 倍精度で使える命令はdiv*やsqrt*で、こっちはもともと有効桁53ビットまで求められる。
ymmレジスタの上位もしくは下位128bitのみを32bit単位で即値でシャッフルできる命令はないのかね
644 :
デフォルトの名無しさん :2012/09/24(月) 20:51:01.41
AVX になっても、結局使うデータ型は、 int 8bit * 16 と float 32bit *4 だけじゃね?
m256は使えたら使うだろ。AVX2じゃないといまいち使いづらい気はするが。
cross lane shuffleはレイテンシ3ってのが微妙
未来予測して先に結果返せというのか。
>>640 AVX使えるマシンが無いからわからないけど、VC2010EEで/arch:AVX使ってコンパイルした場合
_mm_load_si128がvmovdqa、_mm_loadu_si128がvmovdquで、ストアもvmovdqaとvmovdquが
使い分けられていたけど、VEX付いてる時はCore系のloaddquみたいに内部的には同じ命令に
なっててloaduでもアライメントが揃ってたら高速で実行可能なのかな?
いやmov*ps,movdq*に関してはAVXでも区別されてるよ ロード/ストアするサイズでアラインメントが揃ってないと例外が発生する まあ全てにmovups,movdquを使っていてもアラインメントが揃っていれば速度低下はない という意味ではAVXが実行できるCPUでは全てそういう実装になっているだろうけど
650 :
648 :2012/09/27(木) 22:12:28.64
速度低下が無いならアライメント命令の存在意義は…
Nehalem以降等ペナルティが無い実装なら存在意義はない AtomやCore2等ペナルティがある実装なら意義はある
Visual Studio 2008でintrinsics使ってるけど、/Og(自動レジスタ割り当てその他)を 付けたときだけ正しく動作しないようになってしまった…。 こういう場合どのへんを疑えばいいかな?デバッガが使えないからどう攻めればいいか 見当がつかない。 ためしにループ内でメモリに書き出す部分の前や後ろにmfence入れてみたら、今度は プログラム自体が落ちちゃうし。 SSE4.1のコード生成の問題に対するHotfixがあったんで当ててみたけど現象は変わらず。
一応アラインメント揃ってればキャッシュライン境界をまたぐことはないから 明示的にアラインメント命令を使う意義は無くもない
それはアラインメントを揃える意義があるかどうかという話であって movaps/movdqaの意義があるかという話ではないと思うが
はぁ?
いや最近のCPUではmovups/movdquを使って
アラインメントが揃った領域にアクセスしてもペナルティがないから
movaps/movdqaの意義って何なのって話でしょ元々は
>>651
消費電力とか…?
単に互換性の問題だろ
>>653 VS2012でも使えば?
2008世代はMASMに関してはコード生成のバグはかなりあった。
>>653 おまじないでも書けばいいと思うよ。
#pragma optimize("g", off)
>>660 実行順序が変わることで顕在化するバグパターンでもあるかと思ったけど、
やっぱり環境の問題なのかな。
なるべく新しいバージョンでやりたいのはのはやまやまだけど、今回は環境が
VS2008に限定されているんで。
>>661 それがonのときに発生する問題を解決したいわけで。
>>662 Microsoftに言って対応してもらう以外ないだろ
最適化有効にすると落ちるから1日ソース調べまわったが見つからず、 結局OCが原因でしたって経験はあるw 設定時負荷テストはしてたから疑ってなかった。
>>663 つまり?最適化オプションの有無で動作が変わるとしたら
ほぼコンパイラの問題と考えてよいということか。
>>655 スケジューラの都合もあるでしょ。
dqu/upsだと境界をまたぐ可能性があるが、アラインメントがとれてるかどうかは
実際はアドレスを解決するまではわからない。
スケジューリング段階でアラインメントとれてることがわかればRAWハザードの影響を
軽減できる(かもしれない)
>>658 そんなのもあるかもね
最適化で動かなくなるケースのほとんどがソースのバグだけどな
おっとVC++2003をdisるのはそこまでだ
>>666 memory disambiguationで投機実行されるからRAWハザードは影響ないと思うなあ
>>667 興味深い。SSEで発生するケースにはどんなものがある?
>>669 普通アラインメントのとれたロードのほうがレイテンシも短くて済むし
スケジューラの都合的に有利なのは間違いなさげだけどね
それこそ実装依存な気もするが
>>671 もちろん全ての実装で等速なわけではないので
アラインメントが揃ってるのが分かってる場合は
aps/dqaを明示的に使ったほうがいいというのには同意する
とりあえずmovdqaをmovdquに置換してみて遅くならないことを検証してみればいいのかな
674 :
デフォルトの名無しさん :2012/09/30(日) 13:00:08.39
/Og の使用は推奨されてないといっても聞く気はなさそうだが。 モノみないとなんともだが、最小コード書いて動くかどうか見て、それの積み重ねしないとハマるだろ
そりゃ/Ogオプションそのものの話。 Releseビルドのデフォルトに指定されてる/O2は/Og/Os/Oy/Ob2/Gs/GF/Gyと等価。
Core 2以前では、movdquはアライメントの制約が無い代わりにアライメントが揃っていても速度の低下があったから movdqaが用意された訳でしょ。 単体で完結してるアプリならアライメントのコントロールも可能だけど、 ライブラリやコーデックみたいなプログラムだと入力、出力共にアライメントが揃ってるとは限らない上、 独立してずれがあったりするんだよね。 ベクタ長が長くなるだけでも端数処理のために似たようなコードを繰り返し書かなきゃいけないけど、 さらにアライメントを揃えるとなるとmovdqaを使うコードの前にも端数処理コードが必要になるうえに、 それでも入出力の片方のアライメントしか揃えられないことが多い。 概ねアライメントが揃っててデータの個数がベクタ長の倍数になってることが多くても、 保証されていなければmovdqu使って速度低下を容認することが多かったし、 コンパイラでもAVXならメモリオペランド使ってレジスタを節約したりしてるから アライメントの制約の無い命令が常に速度低下しなくなるメリットは大きいよ。
ワーク領域(ヒープ)までアラインメント揃えずに使っていいかっていうとそれは違うよねって話にはなる
678 :
デフォルトの名無しさん :2012/09/30(日) 21:13:41.25
SSE とか、結局 8bit int と 32bit float しか使わないよな。
普通に倍精度使うけど? 整数は16ビットが一番使うような(8bit intってようは1バイト文字だろ)
よほど速度稼ぐという理由が無いかぎり使わないよ。 基本、int32とdoubleで済ます。
単精度使いまくるよ 桁落ちにびくびくしながらだけど
x87を使いたくないだけなんです
処理時間に制限があるプログラムばかり書いているから 単精度でSIMDとOpenMP使う以外ありえないだろって考えになってるな
GPU使えよ
GPU使ってるしGPUも単精度のほうが速いから CPUのコードも自然と単精度で統一される
単精度で総和取るときとかどうしてる? この点thrustはいいね
並列化するとプロセッサの数で総和が変わったりもあるからあまり気にしてないな 金の計算ではないし 誤差に影響を受けにくい手法が使えるから速度を優先できる
688 :
デフォルトの名無しさん :2012/10/02(火) 13:35:58.14
>>685 Sandy-Eが出てからは、GPUに大きなアドバンテージが無くなった。
GPUは補助的に使うようになった。
次はkeplerだろうけど、スペックみたらXeon Phiの方が速そうだし、楽に今までのコードが動かせそうだ。これはかなり重要だしな。
Cell、cudaとやった経験から、やっぱり過去の遺産(技術)は大事だなあと実感する。
GPUなら1万円で1TFLOPSが手に入るのに。
CUDAはプログラミングが面倒だからできれば使いたくない データ転送が遅いから使いどころも難しいし CPUにはがんばってほしい
そこでCPUでもGPUでも計算させれるOpenCLじゃないのか? 同時には無理だったと思うけど。
>>691 OpenCLで書いたプログラムは
CPUだとAVX+OpenMPで書いたものより遅く
GPUだとCUDAで書いたものより遅い
速度を優先するならハードウェア向けに書いたほうがいいし
速度を優先しないならC言語でいいだろって思ってる
OpenCLのコンパイラがハードウェアの専門知識を持って
ガチガチに最適化してくれればいいのだろうが
それができるほど抽象的に書けないし
速いとか遅いとかは、どこかの結果を盲信してないで、自分でベンチを作って自分でやらないと自分が進むべき道を失いますよ。
おまえ以外はみんなやってるよ
だぁらそれはベンダーに依存するっしょって話で、 NVidiaだとCUDAの方が速いだろうが、AMD(ATI)とかだと分からんよね(漏れは試してない)。 みんなNVidiaとAMD両方で検証してるんか、すごいな。
ここまで来ると嘘くせー
699 :
デフォルトの名無しさん :2012/10/04(木) 08:23:32.79
>>695 ATIなんか普通は使わねーよ。
gpgpuていったらnvidia一択だろうが。
nvidiaはsse,avxやx86命令セットをサポートしないんですか?
複雑すぎてプログラミングできんわ
NVIDAのGPUでスパコン作った話は山ほどあるけど ATIのGPUを使った話は聞いたことない あの研究者たちはベンチマークしなかったからNVIDAを選んだのかw まあ暗号の総当りなんかはATIのほうがコスパよくて人気らしいが
NVIDIAな
コスっぱ?
コストパフォーマンスな
それはCPU(Opteron)とかの話で、GPUじゃないんでは? ブルになると浮動小数点系は2コアに1ユニットだから、Intelの方がコスパいいかもしれない AVXとかSSEも2コアに対して1ユニットなんかね
AMD/ATIは非Windows方面のドライバがな NVIDIAのプロプライエタリドライバの方がサポートがましだから
>>702 長崎大のゲフェスパコン作った先生がそのあとCaymanクラスタ作っとるよ
ゴードン・ベル賞とったのはこっちだったはず
n-bodyとか総当りの多体計算だとピークFLOPSで勝るラデのほうが使いやすくパフォーマンスが出るみたいな論文も書いてた
並列化の粒度が細かければSPが多いRADEONのほうが速いのだろうな
>>709 あれはコスパ賞だろう
特別賞とったTUBAME2.0はTeslaクラスタだ
ラデの事例ないのかっていうから出ただけだろう ピークパフォーマンスで受賞したTUBAME2.0と 価格あたりFlopsのコストパフォーマンス賞撮ったDEGIMAクラスタくらべること自体ナンセンスだとおもう
714 :
デフォルトの名無しさん :2012/10/07(日) 14:14:41.69
VisualC++だが、アライメント指定した変数をstd::transform()とかに突っ込むと // error C2719: '_Func': __declspec(align('16')) の仮引数は配置されません。 みたいなエラーが出るけど、これは関数が値型で引数を取ってる為だよね。 どう解決すべき?標準C++ライブラリを改変するのは気が引けるのだが。
>>714 単にテンプレートの展開でVC++が__declspec(align('16'))何かを理解できないからかね?
ポインタで渡してあげるようにすればできると思う。
>>715 std::accumulate()も同様でわかりやすいから例に挙げるが
Ty accumulate(_InIt _First, _InIt _Last, _Ty _Val)
この_Valが値渡しの為に、引数はアライメント出来ないという制約とバッティングしてしまう。
Ty accumulate(_InIt _First, _InIt _Last, const _Ty& _Val)
こうすれば通るんだけど、ライブラリ側直すのやだなって。
717 :
716 :2012/10/07(日) 14:45:53.94
こういうのもそうだけど、 CPUってSIMD使って、カタログスペック底上げするんなら もうちょっと開発言語とすりあわせてもいいんじゃねーかなと思う。 うちのCPUは1Tflopsですよー でも.NETやJavaはダメでーす C++は使えるけどSTLはダメでーす Cは使えるけどfloatもdoubleはダメでーす って実質使えねーのと一緒じゃねーか。
まぁハード屋ってのは今も昔もそういうもんだなw
>>716 これは無理だわ。
stlは多々でさえ並列化が不十分な上、ハードウェアに依存するsimdはなおさらだな。
ただ、stlでもvectorとかであれば、インテルコンパイラなら自動ベクトル化してくるけど。
vc2008 だと問題なく値渡しするようだ。 でも元々アドレスで渡したいんだからポインタを渡せばいいんじゃないだろうか。 > もうちょっと開発言語とすりあわせてもいいんじゃねーかなと思う。 それは C/C++ の規格に言うことじゃないな。そして CPU ベンダーじゃない Microsoft に言うことでもない。 ベンダーの都合で言語の仕様を変えていくと(ライブラリだけど)DirectX8/9 のようなカオスになる。 C/C++ は抽象度が低すぎるせいでうまく融合させられないが、言語にサポートを求めるなら Fortran とか使うと少し幸せになるんじゃなかろうか。 独自拡張の話をすると、vector というキーワードを取り入れているコンパイラがある。 PS3 に搭載された Cell 向けに IBM が実装して、vector char とか vector float のように型宣言できて、レジスタ渡しできたりする。 intrinsics とあわせると、まあ捨てたものじゃないくらいにはなってると思う。 また、arm neon 向けの開発環境だと、int8x8_t とか float4x4_t とか(大元の宣言は __attribute__だけど)、同様に使える拡張があったりする。 SIMD 対応に関しては Cg とか GLSL と比べるとまだまだ足りないけど、ある程度以上を求めるなら、互換を考えると別の言語を作るしかないんじゃなかろうか。
くだらんこと妄想してないで素直にインテルコンパイラ使え
個人や大学の研究に使うんだったらインテルコンパイラはフルバージョンで無料だから使わない手はないな。 仕事でやるなら。。。。少々高いけど、付属のライブらいが再配布可能だからまあよし。 もっともコテコテにインラインASMや組み込み関数を使うならあまり効果はないけどな。 あとBoostやらQtやらのライブラリを使う時は多少面倒かもしれん。
>>722 非商用版はLinux用しかないけど、Parallel Studio XE 2013まであるのか…
今更Ivyを入手したのでzero latency register moveを検証してみた。 クロック計測スレが落ちてたのでこっちに書くけど微妙にスレ違いですまん。 どうも計測してみると、デコード後にmovと後続の依存するuopを ひとつのuopに結合するような挙動をしているように見える。 ・uop fusionのようにデコーダ自体がfused uopを吐くわけではない(これはx86命令として分かれているので当然) ・macro fusionのようにデコード前に結合してひとつのuopを吐くわけでもない(x86命令として連続していなくても結合される) ・zeroing idiomのようにそれ単体でuopが消滅するわけでもない(依存関係の全く発生しないmovを並べても消滅しない) loop: movaps xmm1, xmm0 movaps xmm0, xmm1 dec ecx jnz loop これだとSandyは3clk/loop,Ivyは2clk/loop loop: movaps xmm1, xmm0 movaps xmm2, xmm1 movaps xmm0, xmm2 dec ecx jnz loop これだとSandyは4clk/loop,Ivyは3clk/loop loop: movaps xmm1, xmm0 movaps xmm2, xmm1 movaps xmm3, xmm2 movaps xmm0, xmm3 dec ecx jnz loop これだとSandyは5clk/loop,Ivyは3.33clk/loop <-3clk/loopで回らないのは何故? ともかくBulldozerの実装とはちょっと違うようだ。
ああ、意図がようやくわかった。 movapsもdec+jccもPort5で実行されてて、Ivy Bridgeはmov*の除去が行われるから 2個のmovapsあたり1サイクルで処理できるはずってことね。 1個目は 0: movaps xmm1, xmm0 +movaps xmm0, xmm1 1: dec ecx + jnz loop で2サイクルで処理できるわけだ(実際に処理されるのは後続分) 2個目は多分こう 0: movaps xmm1, xmm0 + movaps xmm2, xmm1 1: movaps xmm0, xmm2 2: dec ecx + jnz loop 問題は3つ目だよね。 0: movaps xmm1, xmm0 + movaps xmm2, xmm1 1: movaps xmm3, xmm2 + movaps xmm0, xmm3 2: dec ecx + jnz loop で3サイクルで回りそうなのにそうなっていないと。 (なぜか4サイクルかかってる場合がある?) レジスタファイルのR/Wポートすうの制限ではなさそうさし、 条件をもう少し変えてみたらわかるかも。
俺はIvy Bridgeのmov除去の仕組みってRenamerでxmm0とxmm1が同じ物理レジスタファイルの エントリを指すように読み替えてるものだと思ってた(Bulldozerって基本的にこの方式だよね) 文字通り「融合」してるのだとしたら、xmm0の中身をxmm1とxmm2に同時にコピーする オペレーションに置き換えていることになる。 これもありえない話でもないか。 どういう実装になってるのかわかるとボトルネックも突き止めやすいのだけどね。
企業秘密です
>>725-726 そういうことです。少なくともリネーミングで除去しているような挙動ではない。
3つめはループの3回に1回4clkかかっている計算。
こんなコードならどうよ、という提案があれば回してみるよ。
結合はサイクルあたり一つしかできないと仮定すれば 4つのmovapsがちょうど4つ組に入ったとき (この確率は1/3だ)、他より1クロック長くなるだろう
730 :
デフォルトの名無しさん :2012/11/18(日) 16:42:26.60
どうも何もx86ベースメニーコアで(何とか)GPGPUと同等まで 持って来ましたドヤァっていうもんじゃないの
やけに遅いな チューニングができてないんかな?
>>732 Phiのコアは1コア当たり2命令/clkで、うちベクトル命令(単純なストアを除く)は1命令だけしか発行できない。
たとえばL1からレジスタへのLoadだけでもベクタ側のパイプを使う。
x86らしくLoad+FMAの融合演算で性能を稼ぐアプローチ。
むしろこの構造で実効8割以上もっていけるだけでも富士通すげーや。
Fermiは16SPに対して8DPだから実効性能比が悪かった。
Kepler2は、24SPのSMXごとに8DPと命令帯域あたりの理論FLOPSをFermiの2/3に落としたから
そら実効値上がるわな。
(もちろんSGEMMの実効性能比は悪いまま)
つか行列積程度の単純な問題ならいまどきのGPGPUでボトルネック生じないでしょ。
むしろそれ以外が重要なわけで。
x86コアにベクトルユニットが乗っかった構造のメリットは、GPUではできないような
複雑な分岐を含むプログラムが書けることだ。
ビッグデータ寄りのサーバサイドプログラミング、たとえばパケットフィルタとかにも使えないかと思ってる
パケットフィルタみたいなものはFPGAでやってるだろうし その領域は無理だろ
ポイントはフルプログラマブルであるということ。 たとえば随時新しいウイルスパターンを更新していくことができる。 ウイルスチェックってN×Mの二次元パターンマッチだからメニーコア向けなんだよね
いろいろ制限多いほうが燃えるくせに。
Larrabeeの命令セット仕様が出たときからFPよりも整数演算性能に着目してたよ
739 :
デフォルトの名無しさん :2012/12/02(日) 13:30:26.40
epi16をps*2に変換する際以下のような手順でやっていますが、 SSE4までの範囲でもっと単純な方法ってありますか? __m128i ival; __m128i ival0, ival1; __m128 fval0, fval1; ival0 = _mm_unpacklo_epi16( ival, _mm_setzero_si128() ); ival0 = _mm_srai_epi32( ival0, 16 ); fval0 = _mm_cvtepi32_ps( ival0 ); // fval1も同様
_mm_cvtepi16_epi32 あたり? とりあえず、最低限ドキュメント読もう。
ありがとうございます。 つい最近までSSE3縛りでやっていたんですっかり頭の中から除外されてました。 ところで、どういう命令があるか調べるのにまとまったドキュメントか本ってないですかね? Intrinsics Guideしか持っていないんですが、これだと欲しい命令の目星をつけないと 調べようがないので。
SEXプロレスリング
チラ裏 フィルタ演算みたいにロード側のデータ多くてストアが少ない処理は ストアのアライメントを合わせてalignrでロードを減らすと効果あるよ。
alignr こんな命令あったっけ??
>>746 palignr(_mm_alignr_epi8)だった。shrdのxmm版みたいな命令でSSSE3から使えるよ。
749 :
デフォルトの名無しさん :2013/04/10(水) 18:42:39.88
たぶん4バイトずつずらしながら16バイトロードを繰り返す…みたいな処理だとpalignrが有効、と言いたいのでは?
しかし非VEXなpalignrの上位側の16バイトを上書き、という仕様は 下位側ほうが良かったと思う場面にばかり遭遇しているのだが
Haswellの話題は無いの?
おれもおもた
最適化マニュアルはHaswell対応にアップデートされてたが IACAはまだだな
やっぱ蓮のAVX2やFMAはつおいのかな?
Haswellの実測のレイテンシ/スループットが掲載された
http://instlatx64.atw.hu/ 4ALU化したものの、4ALU全てに発行できる命令はあまり多くない?
mov, movsx, movzx, not, negあたりは4ポート発行できているように見えるが
mov系は除去が効いてる可能性もある
port0,1の混雑を緩和するのが主な目的かな
シフト量が即値じゃないシフト/ローテート命令が1クロックで実行不可に
スループットも2サイクルになってる理由がよく分からん
整数シャッフルユニットが128bit*2portの構成から256bit*1portになった弊害か
pshuf*/punpck*/pinsr*/phadd*あたりのスループットが低下
pmulld/round*は2ups化のため? 速度半減
SSE2->AVX2でレイテンシやスループットが悪化する命令は少ないが
pmovsx*/pmovzx*/即値じゃないシフト等はレイテンシが2倍
なんか既存コードの実行には不利になっている変更が多い気がするのだが
それでも5%程度はIPCが上がるというのはキャッシュ周りの改善が大きいのだろうか
>シフト量が即値じゃないシフト/ローテート命令が1クロックで実行不可に >スループットも2サイクルになってる理由がよく分からん BMI2のSHLX/SARX/SHRXは2命令同時実行可能でレイテンシ1という謎仕様
なんかの布石なのかねえ
>>755 >シフト量が即値じゃないシフト/ローテート命令が1クロックで実行不可に
Sandyでも遅いよ
Sandyは2-2だったが、Ivyでは1-1に高速化された Haswellで2-2に戻ってしまった
あばちゃー
Nehalemまでは即値もclも変わらなかったはずだが SandyでPRFベースに変えて8bitレジスタの扱いが難儀になったのかね
762 :
,,・´∀`・,,)っ-○○○ :2013/07/06(土) 00:37:53.86
327 X86 :IMUL r16, r16 L: 0.88ns= 3.0c T: 0.29ns= 1.00c 328 X86 :IMUL r32, r32 L: 0.88ns= 3.0c T: 0.29ns= 1.00c 330 X86 :IMUL r16, r16, imm8 L: 1.18ns= 4.0c T: 0.29ns= 1.00c 331 X86 :IMUL r32, r32, imm8 L: 0.88ns= 3.0c T: 0.29ns= 1.00c 333 X86 :IMUL r16, r16, imm16 L: 1.18ns= 4.0c T: 0.96ns= 3.25c← 334 X86 :IMUL r32, r32, imm32 L: 0.88ns= 3.0c T: 0.29ns= 1.00c 前世代からだけど、imm16がついてる命令が軒並み遅いのは解せないね。 なんのためのμOPsキャッシュだよっていう・・・
>>755 4ALU化かと思ってたら1ユニットはArithmeticじゃないのね
論理演算も、Zero Idiom的なケースで実行回避されてるものは速くなってるが
64bitが遅めだから4ユニットで演算してるのかよく分からないな
GPR使う命令は2OPだからmov系だけでもIPCは向上するってことかな
クロック上がってないのを考慮すると多少退化してるね。
次で本気出すつもりだったプレスコみたいな位置づけかね?
Haswellで改善してる例 ivy LOCK ADD [m32], r32 L: 6.28ns= 22.0c T: 7.14ns= 25.00c MULSS xmm, xmm L: 1.43ns= 5.0c T: 0.29ns= 1.00c PCLMULQDQ xmm, xmm, imm8 L: 3.88ns= 13.6c T: 2.19ns= 7.67c VMOVAPS ymm, [m256] L: [memory dep.] T: 0.29ns= 1.00c VMOVUPS ymm, [m256 + 4] L: [memory dep.] T: 1.67ns= 5.83c VMULPD ymm, ymm, ymm L: 1.43ns= 5.0c T: 0.29ns= 1.00c VBROADCASTSS ymm, m32 L: [memory dep.] T: 0.29ns= 1.00c
haswell LOCK ADD [m32], r32 L: 5.59ns= 19.0c T: 6.77ns= 23.00c MULSS xmm, xmm L: 1.47ns= 5.0c T: 0.15ns= 0.50c PCLMULQDQ xmm, xmm, imm8 L: 2.06ns= 7.0c T: 0.59ns= 2.00c VMOVAPS ymm, [m256] L: [memory dep.] T: 0.15ns= 0.50c VMOVUPS ymm, [m256 + 4] L: [memory dep.] T: 0.66ns= 2.25c VMULPD ymm, ymm, ymm L: 1.47ns= 5.0c T: 0.18ns= 0.63c VBROADCASTSS ymm, m32 L: [memory dep.] T: 0.15ns= 0.50c
>>763 デコード側の制限じゃないの?
Pen4も実行ユニットは0.25出るものが、スループット0.33だったりするし
もしかして たぶん どうせ どうやら やっぱり また 逝ってよし オレゴン オレゴン オレゴン オレゴン オレゴン オレゴンか オレゴン ┝━━━━┿━━━━┿━━━━┿━━━━┿━━━━┿━━━━━┥ 88彡ミ8。 /) 8ノ/ノ^^ヾ8。( i ))) |(| ∩ ∩|| / / <マダココ! 从ゝ__▽_.从 / /||_、_|| / / (___) \(ミl_,_( /. _ \ /_ / \ _.〉 / / / / (二/ (二)
>>763 どうせagerが出すInstruction tablesはADD SUB 0.25とか書くだろ
あれはパイプラインとかデコーダの制限は考慮しないからな
>>766 アホか
普通のALU命令も4並列デコードできなかったらCore2より劣化してるだろ
770 :
,,・´∀`・,,)っ-○○○ :2013/07/20(土) 11:16:17.16
デコーダのスループットによる制限は今の命令帯域ベンチに現れないんじゃね? μOPs cacheだし
772 :
デフォルトの名無しさん :2013/07/20(土) 19:12:52.47
>>769 あの測定値によってALU側に制限があると考えるおまえがアホ
>>772 別にALUに制限があるとは言ってねーよ
デコーダに制限があると考えるのがアホだと言っただけだ
そもそもあの手の計測ならuops cacheから供給してるだろうしなおさら引っかからん
追加のALUポートはJccとかの従来port5で発行していた一部の命令を
オフロードするためのものじゃないかな。
最大命令発行数を増やすことよりポート競合によるパフォーマンス低下を防ぐことに
主眼がおかれてるように思える。
後藤はんが解説してるけど、HaswellのRSは60エントリだそうな。
これは普通に考えれば6エントリ×10段分しかない。
つまり、Sandy Bridgeと比べてRSの段数は増えたが1段あたりのエントリ数は
増えてないことになる。
http://pc.watch.impress.co.jp/docs/column/kaigai/20130602_601851.html おそらく1クロック毎に供給できる6μOPsのうちの3μOPsはLoad/Store絡みで
ALUにコンスタントに供給できるのは3オペレーションまでなんだろう。
uops cacheから供給してるなんて保証がどこにあるんだ? > 2 X86 : 2x 0x66 NOP L: [no true dep.] T: 0.07ns= 0.25c > 3 X86 : 3x 0x66 NOP L: [no true dep.] T: 0.07ns= 0.25c > 4 X86 : 4x 0x66 NOP L: [no true dep.] T: 0.09ns= 0.30c > 5 X86 : 5x 0x66 NOP L: [no true dep.] T: 0.11ns= 0.37c この結果を見ると、uops cacheから外れていてデコーダの16bytes/cycle制限に引っかかってるようにしか見えないが。
レジスタ間オペレーションなら1命令5バイトしかないFMA3もスループット0.63cになってるから 正確な数字が出てるともいいがたい。μOPs cacheミスヒットでは説明がつかない事象だ。 本来0.5cだよな。 (まさか8バイトcycleじゃないだろ?) まあ、FMAに関してはxmm版はBulldozer/Piledriverも0.63cなんだが。
>>775 で、add reg, regみたいな命令でどうやって制限に引っかかるの?
そもそも16B/clkはL1Iの制限だがな
簡単に0.25出てるなら売れ行きが鈍いとか問題にならないでしょ
バックエンドのどこかの制限で0.25が出ないのに加算器だけ4つ積んだって無駄と言えなくもない
レジスタ増えてuOPキャッシュでデコーダの制限も緩和されてるのにIPCが増えないのは何か制限があると思うな
ポート6以外はSIMDでも使うから256bit演算のディスパッチに失敗するペナルティは大きいのではないか?
それを回避するためのGPmovのバイパスという設計なんかね?
>>775 ALUとuOPキャッシュのベンチ結果が混ざった状態にするかね?
780 :
デフォルトの名無しさん :2013/07/21(日) 19:20:35.97
>>778 この結果を見ればデコーダーの制限と見るのが自然だな。
コンプレックスデコーダを使うまでもない、単純命令はシンプルデコーダーオンリーで処理されるから3命令デコード止まりだというのが大原氏の考えらしいが、
俺もそう思うし、それを匂わすことが最適化マニュアルにも書いてあるよな
>>779 俺はデコーダーの制限をHaswellで取っ払うと思っていたら、そのままなので、Intelはよほどコンプレックスデコーダーを動かしたくないんだなw
>>780 > それを匂わすことが最適化マニュアルにも書いてあるよな
それってどの記述?
>>780 uOPキャッシュの利点はPen4みたいにデコーダ1つでもまともに動くってところなんだから
デコーダの制限が結果に現れてるならPen4のスループットが高すぎるよ
>>782 問題点は何かというと、
>>755 の計測結果が1ループ何命令(計何バイト)で計測してるのかが分からないということ。
Pen4のトレースキャッシュは12kuOPsで、HaswellのuOPキャッシュは1.5kuOPs。
仮に1ループ2000命令で計測していたとすれば、
Pen4ならトレースキャッシュにヒットしまくり、HaswellだとuOPキャッシュミス多発という事になる。
>>783 確かにそうなんだけど、Pen4のuOPキャッシュの容量は
>TC can hold up to 12-Kbyte μops and can deliver up to three μops per cycle.
Kbyteで換算してるんで、そこまで大きくなかったと思う
サイズ自体は同等だったような
>>778 のグラフ14でデコード帯域8*4byteになってるからALUはちゃんと搭載されてるみたいだね
となると、リネームかレジスタファイルのアクセスがボトルネックになってるのかも
公式マニュアルのトレースキャッシュのサイズ表記まちがえてるだろ、これ。 古いCPUだから中の人間違えたか。
今の最適化マニュアルのその記述は誤植。もともとの正しい記述はこれ。 > In the Pentium 4 processor implementation, the TC can hold up to 12K μops and can > deliver up to three μops per cycle.
787 :
デフォルトの名無しさん :2013/07/21(日) 23:53:52.37
Haswellの4ALU化はuOPキャッシュにヒットした時の効果だけを狙ったものだろうな
>>775 の結果はuOPキャッシュの効果が見えてないけど、それなりに4ALUの意味はあるじゃないの
Pentium 4の実行トレースは12kμOPs = 128KB(Prescottの場合) 1μOP=1バイトなわけねーしwww
>>781 こんな記述がある
3.4.2.1 マイクロフュージョン向けの最適化
インテル® Core™ マイクロアーキテクチャーおよびインテル® マイクロ
アーキテクチャー Sandy Bridge では、2 マイクロオペレーション(μOP)からなるフロー
をデコーダー0 から供給する。2 マイクロオペレーション(μOP)のフローをアライメン
トの合ったデコーダーからデコーダー0に移さなければならないので、デコード帯域幅の
わずかな損失が生じる。
あたかも初めからシンプルデコーダーのみを動かしている前提の話だよな
いやそれは複数uopに分解される命令はcomplex decoderでしか処理できないという話だろ complex decoderで1uop命令も処理できないとC2DでもNehalemでも4uop/clk出る根拠にならんぞ
マニュアルより >There are four decoding units that decode instruction into micro-ops. >The first can decode all IA-32 and Intel 64 instructions up to four micro-ops in size. >The remaining three decoding units handle single- micro-op instructions. >All four decoding units support the common cases of single micro-op flows >including micro-fusion and macro-fusion.
つーか、このスレにいながら、
>>791 程度のことも
みんな把握してなかったんだなw
そのスレの住人はみんなほんとにアセンプリで最適化したコードとか書いているのか?
>>791 は当然知っているものと思っているが。
complex decoderではシングルμOPの命令もデコードする能力があるが、
あえて休ませているというのが
>>780 の主張じゃなかったのか?
いやだから 110 X86 :SUB r32, r32 L: 0.07ns= 0.3c T: 0.07ns= 0.25c 111 AMD64 :SUB r64, r64 L: 0.07ns= 0.3c T: 0.07ns= 0.25c 114 X86 :SUB r1_32, r2_32 L: 0.29ns= 1.0c T: 0.09ns= 0.31c 115 AMD64 :SUB r1_64, r2_64 L: 0.29ns= 1.0c T: 0.10ns= 0.33c 154 X86 :XOR r32, r32 L: 0.07ns= 0.3c T: 0.07ns= 0.25c 155 AMD64 :XOR r64, r64 L: 0.07ns= 0.3c T: 0.07ns= 0.25c 158 X86 :XOR r1_32, r2_32 L: 0.29ns= 1.0c T: 0.08ns= 0.28c 159 AMD64 :XOR r1_64, r2_64 L: 0.29ns= 1.0c T: 0.09ns= 0.31c この結果を見る限り、zeroing idiomsが適用される限り4uop/clkで動いてるんだから 仮にこの結果がuop cacheにヒットしないコードサイズで測ったものだとしてもcomplex decoderも仕事してるのは明らかなんだよ zeroing idiomsが効かなくなるとスループットが落ちるということは、リネーム以降で何らかのボトルネックがあるとしか読めない
>>789 マイクロフュージョンが実装される前は「わずかな損失」でもなかったよ
SSEの初期はaddpsとmulpsがユニットが分かれてるのに交互に命令が実行されるような
スループットしか出なかった
addssが倍のスループットになってるからpsはuOP2つ発行してたんだろうな
>>794 3ALUになった時もレジスタの同時使用数制限の話はあったからね
uOPキャッシュでREXの影響も軽減されてるはずだからデコーダの問題とは思えないな
150 X86 :OR r1_32, r2_32 L: 0.29ns= 1.0c T: 0.08ns= 0.28c orはdependency breaking idioms的な何かが入ってるのかもよ
この計測プログラムのソースを見ない限りは これ以上議論しても無駄だね。変則的な結果が多すぎる。
QueryPerformanceCounterとかで計測してるんだけど、 計測結果の変動幅がすごく・・・大きいです・・・で困ってる。 あれって他のタスクとかで割り込まれてるからなんかな? 計測対象のプログラムが動いてるスレッドだけで浪費したクロック数を出せたらもっと安定するだろうに。 QueryPerformanceCounter自体も最近じゃCPUのクロック数じゃなくて、 マザボのカウンタ使ってて、本当にCPUがどれだけのサイクル喰ったか分かんねーし。
rdtscで測ってるけどturbo boostに注意すべきという点以外は別に不安定な結果は出ないよ Windowsでどうだかは知らんけど
freeのunixで、kernelの中で割り込み禁止して測ればいい
えっ?!次世代来ちゃうの?
x,y,zときたら1024bitのレジスタはなんという名前になるのでしょう
うひょ〜、512bitマンセー♪
Xeon Phiに512bitのAVXあったやろ
一般人が気軽に買えるところに降りてくるのが素晴らしいんだよ。
少なくとも14nmの世代で一般に降りてくる可能性は低そう
1024bitSIMDハァハァ・・・
x64の呼び出し規約ではxmm6からxmm15は不揮発性になってるけど、 vzeroupperした後で上位128bitを戻したらまたAVXステートになっちゃうから ymm6やzmm6とかに関しては揮発性ってことでいいのかな?
Windowsでは下位128bitだけnon-volatile 行き当たりばったりのクソ仕様
>>811 >下位128bitだけnon-volatile
後からAVXが登場したとはいえ、行き当たりばったりな仕様ですか。
AVX用にコンパイルすると、スタックのアライメントも32バイトに調節してて、
フレームポインタも必要になってしまうのね。
スタックのアライメント調節されるのは__m256や__m256iをローカルに確保している場合で、 xmmだけならやらないようですな。
ということで、これもIPC4 vpaddq ymm0, ymm8, ymm14 vpaddq ymm1, ymm9, ymmword ptr [rbp] vpsrlq ymm2, ymm10, 1 add rsi, rax これもIPC4 add rax, r12 add rbx, [mem1] add rdx, r13 add rdi, [mem2] でもこれはIPC3近くまで落ちてしまう。 add rax, r12 add rbx, [mem1] add rdx, r13 add rdi, [rbp] これもIPC3程度になる vpaddq ymm0, ymm8, ymmword ptr [mem1] vpaddq ymm1, ymm9, ymmword ptr [mem2] vpsrlq ymm2, ymm10, 1 add rsi, rax バックエンドにも多少制限がありそうだけど原因は不明。
[memX]ってなんのアドレッシングモードなの? 初心者ですまん。
>>816 MASM64でコードセグメント内の定数のアドレスを指定した状態です。
_TEXT64 segment page 'CODE'
align 64
mem1 qword 0h, 0h
mem2 qword 0h, 0h
mem1,mem2はそれぞれ16バイトの0で、 ymmword ptr [mem1]とymmword ptr [mem2]はそれぞれ32バイトの読み込み ということは、読み込み領域が重なっているということ?
>>816 たぶんRIP相対アドレッシングって名前
AGUからは遅延なしでパイパスうけられるけど、 レジスタ直接アドレスだとAGU使わないから、Load Bufferかなにかからアドレス値よむから遅延とか? んなわけないか。 ・レジスタファイル ・リタイアメント ・フォワーディング のいずれかではあろうが。
でも、本当にRIP相対ならレジスタよまないからレジスタのポート関係かなあ。
814で速度低下しないということはリードポートの制約ではないような
>>819 AVX2コードの
vpaddq ymm0, ymm8, ymmword ptr [mem1]
vpaddq ymm1, ymm9, ymmword ptr [mem2]
vpsrlq ymm2, ymm10, 1
add rsi, rax
mem1、mem2を32バイトでアライメントしたらIPC 4になりました。
御指摘感謝。
謎なのはAVX2のコードはこれでもIPC 4なのに、
vpaddq ymm0, ymm8, ymmword ptr [rbp]
vpaddq ymm1, ymm9, ymmword ptr [rbp+32]
vpsrlq ymm2, ymm10, 1
add rsi, rax
x64の場合は以下の両方ともIPC 3になってしまうこと。
add rax, r12
add rbx, [rbp]
add rdx, r13
add rdi, [rbp+32]
add rax, r12
add rbx, [mem1]
add rdx, r13
add rdi, [rbp]
最適化マニュアルではPort7がSimple_AGUになっているけど、
AVXでは整数ユニットが空いていてアドレス計算が同時にできるのだろうか。
x64ではIRP相対だけだとIPC4なのに片方が間接アドレスになると遅くなるのが不思議。
load-opのaddじゃなくて普通にadd reg, regを4つ並べるとどうなるん?
>>825 レジスタやIRP相対、レジスタ間接まではaddでもcmpでも差があるようには感じなかったけど、
インデックスレジスタを使用したらどちらも遅くなるものの、addの方が少し速い結果に。
これが3.1clock,2.6IPCで、
add rax, r12
add rbx, [rbp+r13+8]
add rdx, r14
add rdi, [rbp+r15+16]
add r8, r12
add r9, [rbp+r13+96]
add r10, r14
add r11, [rbp+r15+112]
cmpでは3.7clock,2.2IPCに。
cmp rax, r12
cmp rbx, [rbp+r13+8]
cmp rdx, r14
cmp rdi, [rbp+r15+16]
cmp r8, r12
cmp r9, [rbp+r13+96]
cmp r10, r14
cmp r11, [rbp+r15+112]
フォワーディングの効果でレジスタファイルのread負荷が軽減されたのかと
src側をr12とrbpのみに変更しても速度の違いはなさそうだった。
827 :
デフォルトの名無しさん :2013/07/28(日) 15:52:08.08
SIMDだとインデックスレジスタ付きでも2.8clock, 2.86IPCと多少速かった。 vpaddq ymm0, ymm8, ymmword ptr [rbp+r8+32] vpaddq ymm1, ymm9, ymmword ptr [rbp+r9+64] vpsrlq ymm2, ymm10, 1 add rsi, rax vpaddq ymm3, ymm11, ymmword ptr [rbp+r10+96] vpaddq ymm4, ymm12, ymmword ptr [rbp+r11+128] vpsrlq ymm5, ymm13, 1 add rsi, rdx
Haswell面白そうだな Sandy Bridgeセカンドマシンにして買ってみるか
どうもSandyで測ってみると
port0,1,5に発行されるALU命令が必要とするクロック当たりのソース整数レジスタのポート数によって
port2,3に発行される(AGU行き)命令のスループットが制約を受けるような挙動をしている気がする
想像するに
>>824 の「x64の場合は以下の両方ともIPC 3になってしまうこと。」の例で
add rax, r12
add rdx, r13
を
add rax, 1
add rdx, 1
とかの即値加算にするとIPC=4になるのではなかろうか
PRFのポート構成ってどうなってるんだっけ?
MMXレジスタ間のmovdについて質問させてください。 Visual C++ 2010のインラインアセンブラを使用しています。 movd mm0, src1 psllq mm0, 32 movd mm1, src2 movd mm0, mm1 上のようなコードを書き、mm0の上位32bitにsrc1を、下位32bitにsrc2を格納したいのですが、 4行目 movd mm0, mm1 の部分で "error C2415: オペランドの型が無効です。"というエラーが出てしまいます。 どのようにすれば解決できるのか、どなたか教えてください。
リファレンスくらい読めよ
>>829 Haswellで
>>824 のaddの二つのレジスタオペランドを即値にしたら3・4番目ともIPC4になりました。
>>824 のレジスタ同士の加算の片方だけを即値にすると2.2clk,3.6IPCになります。
インデックスレジスタを使うと遅くなり、
>>814 ではcmp、add共に問題がないので、
AGUでレジスタ参照があると影響が出やすいようですね。
SIMDでは影響が出にくいのはPRFが分離されていて参照数が被らないのも一因でありそう。
確認乙 NehalemまでのRegister Read Stall的な何かがSandy以降にもあるのかね この制約が言及されてる文献ってあるのかな Agnerマニュアルにも載ってないし ともかく当初の話題であるHaswellのALUについては 加減算比較論理はport0,1,5,6全てにあり、レジスタオペランドを使う限り 特にボトルネックはなく動くという認識でいいのかな instlatx64の結果は測定方法がおかしい?、ということになるが
>Agnerマニュアルにも載ってないし 特に制限が無かったって書いてあるけど IntelがALUという場合、加算論理移動比較テストあたりまでだな。 AMDがALUという場合、シフトやLEAも入るけど。
うん、だから今回話題になったような制約には言及してないと言いたかったんだけど 伝わらなかったかね
addは4命令フルにリタイアしてるからレジスタファイルの書き込みは大丈夫そう。 計算結果が後続の命令のオペランドにならないcmpでも問題ないので 読み出しもレジスタ同士なら4IPC可能で、メモリ参照も直接アドレスを指定すれば 速度低下はしていません。
>>839 814の8命令シーケンスを512回展開したら2.36clock,3.4IPCになりました。
レイテンシは、下のコードのoffsetを4096と8で比べても差がなくてよくわからないな…
align 64
table qword N dup (0h)
lea rsi,table
mov ebx,8
loop:
mov rax,[rsi+offset]
add rax,rbx
add rsi,rax
>>841 814の8命令シーケンスをaddに替えてってこと?
というのも
>>778 の結果だとNOPやXORはuOPキャッシュミスしても4IPCをキープできるけど、
SUBやTESTやCMPは3IPCに落ちてしまうようなので、他の命令はどうなのかと思って。
ふと思ったんだけど、このSUB,TEST,CMPっていずれもマクロフュージョン対象命令であり、
NOP,XORはマクロフュージョンの対象じゃないなと。
マクロフュージョン対象命令は次の命令が条件分岐命令かどうか確かめる必要があるので
デコードになんらかの制限でもあるのかなぁ?と想像したもので。
offsetは2K未満と以上で差がなかったですか。
HaswellではSandyBridgeのAGU制限がなくなったということなのかな?
>>842 addでもcmpでも変わらないですね。
レジスタ間xorはuOPミスヒットでも4IPC出てるみたいです。
やはり通常、単純命令はデコード3基しか回らないんだろうな コンプレックスデコーダーを使う命令が来れば4基動くかも、って感じなんだろう
3基しか回らないなら3IPC以下になるはず それにxorとかzeroing idiomsが効く命令で4IPC出る理由にもならない
というか、Sandyでもadd reg,reg3つとmov reg,mem(RIP相対)で4IPC出るんだよね普通に 当然全部simple decoder行き命令だがuop cacheにヒットしないケースでもIPCは落ちない
今のところすべての事象を合理的に説明できるのは port0,1,5,6全てに命令が発行されると何クロックかに1回デコーダがサボる という仮定だが
>>846 その例だと、mov reg,regがコンプレックスデコーダー、add reg,regがシンプルデコーダで
デコードしていると言えてしまうのでは。
add reg,reg 6つとmov reg,mem 2つとか、
add reg,reg 9つとmov reg,mem 3つとかの場合で、
uop cacheをミスさせたらどうなる?それでも4IPC出るなら
add reg,regがコンプレックスデコーダーでデコード出来ている証拠になるけど。
>>847 843で
> レジスタ間xorはuOPミスヒットでも4IPC出てるみたいです。
という事なんだから、
port0,1,5,6全てに命令が発行されもデコーダはサボっていないようだが。
>>845 100%uOPキャッシュミスしてる訳ではないので、3IPCを超えるのは別におかしくない。
あとzero idiomsは関係ないかと。xor eax,eaxとsub eax,eaxは共にzero idioms
だけど、xor eax,eaxは4IPCキープ、sub eax,eaxは3IPCに低下。(
>>778 )
>>846 ああなるほど、simple decoderでしか処理できない命令と、complex decoderでしか処理できない命令と
その両方で処理できる命令の3種ある、ということね
>>850 >>755 の結果ではsubがzeroing idiomsが効く場合のみ4IPCになってたからその話をしてたのだが
まあこれはどんな条件で測ったか分からんから何とも言えんか
でもって、Sandyで代表的な1uop命令を測ってみたところ
and, add, sub, cmp, test, inc, dec
はsimple decoderのみで処理可能な命令で
or, xor, not, mov, movsx, lea, shl, shr, sar, neg, SSE/AVX命令群
はsimple/complex両方で処理可能な命令、ぽい
で、よく考えてみると、前者は全てmacro fusionが可能な命令で
後者にはmacro fusionが可能な命令は含まれていない
ということで
>>842 の推測は正しそう
cmpとtestしかfusionできないCore2,Nehalemではどうなのかも調べないといかんね
Ivyまでならバックエンドと同じ帯域なので大した影響はないとは言え
一応これも4-1-1-1ルールに引っかかるようなので命令の並びによっては若干IPCに悪影響があるね
どうやって測ったんだ?
>>852 やはりそうでしたか。
手持ちのマシンのCore2ではcmpとtestは4命令同時デコードできているようです。
確かめた方法は
test eax,eax×24連続,mov ecx,[edx]×8連続,test eax,eax×24連続,mov ecx,[edx]×8連続,...
のコードで4IPC出る事を確認。cmpも同様。
Sandy以降、コンプレックスデコーダでマクロフュージョン対象命令がデコードできなくなった
という事なら、最適化マニュアルの「4uopsまでのすべてのIA-32,Intel64命令をデコード可能」
という記述
>>791 は誤りになるね。
Nehalemでも同様。ということでSandy以降の制限のようだ。 こういうIntel流の細かいサボりがトランジスタコストを下げて電力効率を上げてるんだろうなあ...
3命令しか実行できなかったんだから、3命令デコードで問題なかったんだろ 実際Haswellが出るまで誰も問題にしなかった そのHaswellの4命令実行はμOpsキャッシュからの供給を当てしたものだった 実際μOpsキャッシュは80%のヒット率があるなら大半これで間に合うという判断だろうな skylake以降は残り20%の対策をしてくるだろうけどな
>>844 ,845
xorを1ループ4096命令並べたバージョンでも4IPC出てるのは下のようにオペコードの短い
32bitレジスタを指定したレジスタ間xorの場合で、
>>814 の命令をxorにして4096並べたバージョンでは
2.2clock,3.6IPCでした。
テストに使っているプログラムはいずれも64bitモードで、32bitモードは試していません。
xor eax, ebx
xor edx, ecx
xor esi, ebp
xor edi, ebx
xor eax, ebx
xor edx, ecx
xor esi, ebp
xor edi, ebx
>>778 ではuOPキャッシュの繰り返しのサポートを推測しているけど、
uOPキャッシュって再度実行するためにデコード結果を格納しておくものだから
ループでなければキャッシュしても仕方ないよね。
ということは、単なる擬似LRUだけではなく、ループ内と判定された部分はキャッシュから
消去されにくくなってる可能性はない?
>>857 じゃあ32bitレジスタを指定したレジスタ間addを1ループ4096命令並べたら場合はどうなるの?
>>858 add,cmp,subは64bitレジスタと32bitレジスタはどれもほぼ同じ速度で、
64bitレジスタ間だとほんの僅か速い傾向です。
r8d-r15dを使った場合はどうでしょう
>>860 REX.Dは64bitレジスタと同じ結果になりました。
xorでも2バイト命令は4IPCで、3バイト命令だとIPC落ちるということかな。 なんかいろいろと制限ありそうだね。
Sandyだとプリデコーダの制約が見えてる気がする 16バイトあたり4命令に近いほどスループットが高い感じ (4命令で16Bを超えない限りREXが付いたりと命令長が長いほうが速い) Core2だとマニュアルにも載ってる16Bあたり6命令/clkのプリデコーダ制約があったけど Sandyでも2B*3+4B*1の繰り返し(7命令/16B)だと3.2IPCぐらいしか出ないから 似たような制約があるっぽい (Ivyも同様) Haswellで2B*4の繰り返しで4IPC出るなら改善されたことになるが
もしプリデコーダの並列度が6->4になってるとしたら 最も影響が出るのは3B命令の連続じゃないのか 2Bと4B以上は変わらんし、1Bは仮に変わってもわからんだろう
ああ、確かに2B連続なら結局2サイクルで8命令プリデコードできるから影響ないな 失礼
>>778 のprefixed cmp(8)の場合、7バイト超えているからコンプレックスデコーダでしかデコード
できないはずなのにかなりのパフォーマンスが落ちにくくなってるよね。
例えば、グラフ14の8*1.5kuOPになる12KB以上の部分はuOPキャッシュが機能しているのを示していて、
これは分岐予測やループ検出の応用でuOPキャッシュのヒット率が上がっているの示しているんじゃないか?
>>863 7命令だと6命令と1命令でプリデコードに2サイクル掛かるからそのくらいで妥当じゃないの?
7バイト超の命令はコンプレックスデコーダでしかデコードできないなんて制限あったっけ? Core2でRMMA実行してみたけど、Prefixed CMP #1〜4 どれも16bytes/cycle出るので、 シンプルデコーダでもデコード出来ているようだが。
>>7 バイト超の命令はコンプレックスデコーダでしかデコードできないなんて制限あったっけ?
そんなのPenproの頃の制限
PenProの頃はあったのか。
>>868 ,869
グラフ14のIvyの100KB付近は1IPCになってるけど。
100KBという事はL1命令キャッシュもミスするから、 それくらい遅くなるのは不思議じゃないと思うが。
>>867 なので似たような制約があるっぽいと書いたつもりだが
しかし、クロック計測スレが落ちてしまったのが悔やまれるな
まぁHaswellはL1命令キャッシュミスしても16bytes/cycle出るようになったのはすごいやね。 これの効果が出てるということだろうね。 > Haswell の命令cache は、miss をより高速に扱えるように最適化された。投機的なITLB > とcache access がprefetch の恩恵を向上すべくより優れたtiming でsupport されるに加 > え、cache controller が命令cache のmiss を並列に扱うこと関して、ずっとより効率的に > なっている。
>>778 だとL1Iミス以前から速度が落ちてるからデコーダの制限じゃなかったですね。
>>876 HaswellだとL1IからL2の間のサイズでの改善が素晴らしいなぁ。
>>840 実は公式の最適化リファレンスマニュアルにも書いてある。
base+offset < 2048ってbaseも含まれるかのような微妙な記述なんだよな。
base+offset < 2048のときがたまたま速くなってしまうだけで、通常のケースは5 cycleってニュアンスの可能性もありえなくもないw
詳しくは、Table 2-12.とその周辺の文を参照。
880 :
デフォルトの名無しさん :2013/08/06(火) 20:44:56.94
>>870 PenProどころかPenMもそうだよ
最適化マニュアルに書いてある。
HaswellのWindows8マシンにCodeAnalystをインストールしたらOSが起動しなくなった。 セーフモードではアンインストールができずに詰んだかとも思ったけど、 セーフモードでレジストリエディタを起動して、 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CA_なんたら のサービスの2つのキーのStartエントリを4に変更することで起動に成功した。 CodeAnalystは開発が終了しているので、HaswellマシンにはCodeXLを使いましょう。
VC2012 x64コンパイラの_mm256_extracti128_si256バグにハマってしまった。 当面は_mm256_extractf128_si256使って回避した方がいいよ。
情報サンクス!!
そう言えばCode Analystを入れている時にパイプラインが途切れている場所を 発見する度に(´・ω・`)となっていた記憶があるな もう入れてないや
俺も試しにCodeAnalystをインスコ・・・う、動かん orz XPはもうサポート外なんすね。少し旧い3.4落として入れたら動いた。
HaswellのSIMD命令組み合わせの影響を調べてみた。 www1.axfc.net/uploader/so/3012766
866はTBが効いた状態になってるから少し数値がずれちゃってる。 さっき電源オプションでプロセッサの最大状態を99%にしたら切りのいい値になったから これだとTB無効にしたのと同じ結果になるのかな?
gather遅い… マイクロコード実行で他の命令が阻害されてるのか、maskmov的な機能がオーバーヘッドになってるのか、 レイテンシが長くなりがちな上位レーンを先に処理しないからなのか… SIMD掛け算やymmのレーン間をアクセスする命令のレイテンシも前の世代より長くなってるみたいだから そこがクリティカルパスにならないように工夫しなくては… gatherに似たアプローチでデータをかき集めるより、部分的なSoA形式で並列化と局所化のバランスを 取るのがいいのかな。
gatherって明らかにレイテンシかかりそうな処理だよね。 やっぱ隠蔽するにも限界があるのかな。
複合命令でも必要なレジスタが少なくて済むのは便利だっだったりするんだけどね。 要素が順番に並んでないとデータ並列化のオーバーヘッドが無視できなくて、 完全にSoAにして要素が多数のページに分散するとメモリアクセスがボトルネックになる可能性があるから スプリットマイニングの要領でSoA形式に変換した方がいいのかなって思ったり。 ポインタ計算をAVX2でやると32bitと64bitのコードを変更しなきゃならないのは面倒か…
gatherとかはお試し実装みたいな感じで SkyLakeでかなり改善されるらしい
Agnerの最適化マニュアルが更新されてIvyやHaswellへの言及が追加されたね 実はこのスレでHaswellの4ALUに関する議論があった後に Agnerのblogでmacro fusion可能な命令のデコード制約について議論したのだけれど その制約について新たに言及されるようになった (microarchitecture.pdf、124ページ) ようで 議論に参加した皆さんありがとうございます
末尾デコーダにfusion可能な命令がくると保留されて次のクロックに第1デコーダで処理されるって? そんなアホな実装あるかなあ 後ろにjccがあってトントン、なかったら丸損なんだから 単純に一命令として処理した方が得じゃん
894 :
片山博文MZコスモ ◆T6xkBnTXz7B0 :2013/09/15(日) 13:25:16.36
「VEX.NDS.128.66.0F.WIG」 この意味を教えて下さい。
896 :
片山博文MZコスモ ◆T6xkBnTXz7B0 :2013/09/16(月) 17:27:55.98
AVXって32ビットCPUでも使えるの?
Intelのマニュアル読めよ
Piledriverちゃんのネタ感が The Piledriver is particularly bad on 256-bit stores with a throughput of one 256-bit store per 17 clock cycles in my measurements (aligned). 17サイクルに1回って… The throughput for 128-bit FMA3 instructions on Piledriver is one instruction per clock, while the throughput for 128-bit FMA4 is two instructions per clock. 何が起こってるの…w
まあ、SSEのときからStoreは極端に弱かったからね。 > The throughput for 128-bit FMA3 instructions on Piledriver is one instruction > per clock, while the throughput for 128-bit FMA4 is two instructions per clock. これはひょっとしたら故意に性能を落としてるかもしれない(FMA4を使って欲しいがため)
ユーザーがAMDのCPUを使うこと自体に興味を失ってしまっては元も子もないけど。 Haswell-EXが出るまでに256bit化しないとHPC界隈からも見捨てられる気がする。 AVX-512って実質的なYMM32レジスタ化だよな
902 :
Socket774 :2013/09/16(月) 22:56:39.55
steamrollerで256bit化するっぽいけど、今でさえ高い消費電力が、 256bitFPUでフル稼働したらとんでもないことになりそうだ。 しかもスチームってフロントエンドも二重化するらしいし。
メモリオペランドが複数の命令に分解されるのと一緒じゃないのかな。 Intelはmove eliminationでFMA3でも大丈夫だと判断したんだろうとあったから、 FMA4の実装してたら同じことになってたのかもね。 Intel CPUにはFPユニットのWarm upペナルティというのがあったから AMDでも単純に消費電力が増えるわけでもないだろうし、 HaswellもOCCTではかなりの爆熱状態になるよ。
> FMA4の実装してたら同じことになってたのかもね。 元々FMA4自体はIntelが最初に計画したものでFMA3のほうが後から 変えたものだ。 しかしimm8をレジスタオペランドとしてとる命令は複合デコーダパスだから μOPs cacheを外すと極端にスループットが落ちることは現実問題として あり得たと思う。 FMA3の最大のメリットは、3レジスタオペランドならシンプルデコーダでも それほど手を入れなくてもデコードできることだろう。
905 :
Socket774 :2013/09/16(月) 23:22:58.08
だからだよ。 Haswellでさえそうなんだから、steamrollerじゃ悲惨だろ
steamrollerはHotChipsの128-bit FMACと書いてあるスライドしか見たこと無いな あれからデータパスを1から作り直してるのか?
>>890 亀だけど
> ポインタ計算をAVX2でやると32bitと64bitのコードを変更しなきゃならないのは面倒か…
へ?
ベースアドレスは汎用レジスタで持てばいいからYMMレジスタにはそのオフセット(添字)の
配列を格納するだけでいいはずだけど?(32ビットでたいていは足りるよね)
vgatherを使ったコードでも32ビットと64ビットでそれほど書き分けは必要ないはず。
↑Intrinsics使う前提ね
909 :
デフォルトの名無しさん :2013/09/22(日) 13:16:50.45
__m128の配列を宣言する場合、__m128といえど 16バイト境界に置かれないので__declspec(align(16))で修飾しなければならない。 void func(){ __declspec(align(16)) const __m128 v[10];} これはstatic配列でも同じですか? void func(){ static const __m128 v[10]; // __declspec(align(16))は必要? }
>>909 そもそも_m128にalign(16)の宣言がついてるからいらないのでは
初心者質問おk? VS2010のコンパイラ組み込み関数で 128 bit整数 0x11111111 22222222 33333333 44444444 uLLLを __m128iにセットするにあたり _mm_set_epi32(0x11111111, 0x22222222, 0x33333333, 0x44444444) とやれば事足りると思うんですが、 これとは別に _mm_setr_epi32(0x44444444, 0x33333333, 0x22222222, 0x11111111) とやっても結果・吐かれるアセンブリコードともに違いが無いみたいなんですが なんでset系はr無しとr有りの二種類あるのですか (特にr系の存在意義とか知りたい。)
書き方の好みの問題。 いわゆるシンタックスシュガー
>>911 int i[4] = {0x44444444, 0x33333333, 0x22222222, 0x11111111};
それを32bit整数の配列で表すと、こうなる。
これと同じように、アドレスの小さい順に書きたいことも多い。
914 :
911 :2013/11/05(火) 07:04:52.90
シンタックスシュガーっぽいのはコンパイル時に値が確定してるからじゃないのかな さすがに関数を指定したら生成コード変わるでしょ。
ふとオモタが、__stdcallな呼び出し規約が標準であるPascal系等の言語から 直に_mm_setr_XXXX()を呼ぶと_mm_set_XXXX()と同じような感じになるのではないだろうか… 糖衣構文も、それなりに理由があるからこそ設けられるのだと思うし… ていうか、ぶっちゃけ次の質問なのですが、現実問題として_mm_empty()っていつ書けば良いのですか? MMX命令を使い終わってからFPレジスタを使い出すまでの間っぽいことが書いてあるのですが、 そのポリシーを、中でFPレジスタを使っているのか否か定かでない他人様のコードとの 混在状況においてまともに順守するとなると、他人様のコードを呼ぶ前に必ず書かねばならないという こと?
基本はできるだけFPU命令はFPU命令でまとめる、MMX命令はMMX命令でまとめる。その上で、 ・MMX命令(群)を実行するまえにFPUレジスタスタックを空にしておく。 ・FPU命令(群)を実行するまえにEMMS命令(=mm_empty())を発行しておく。 質問については、いろいろやり方はあると思いますけど、、、他人様のコードの動きがわからなくてそもそもうまくいくのかな? 参考) ・x86アセンブラ入門(CQ出版..pp222) ・Intel Software developper:s manualのEMS命令の項
MMX使わないなら書く必要は微塵も無い。 てか今更書く必要あるの?64ビットだとMMX関連はコンパイルエラーになるんだが。
団子さん、今でもアセンブラやイントリでガリガリ書くことある? もうSIMD以外使う意義なくね?
bsr/bsfとかpopcntみたいな特殊なビット操作を組み込み関数なしでできるなら できればそうしたいな。 まあ、使うケースとしてSIMDと併用することが多いんだが。
921 :
919 :2013/11/07(木) 00:20:57.96
やっぱSIMDだよなぁ。 512bitSIMD楽しみだ。
MMXはSSE2整数系の命令に代替できるんだっけ?
なんか足りないのある?
足りてる
_mm_packhiとか_mm_unpackhiはレジスタの長さが変わると影響を受けるよ あとSSEはメモリオペランドのアライメントが合ってないと例外になるとか
そーいやXeon Phiのミスアラインロードが妙に使いにくいようだが・・・ アラインメント境界とキャッシュライン境界が一致するからあんな感じなのかな
927 :
916 :2013/11/10(日) 03:45:14.56
レスdクス、
いまいちMMXとSSEとSSE2とその他とAVXの区別がついていなかったのですが、
Intel様がタダで配っている次のイントリンシック命令分類アプリで見たら色分けされてて大変良くわかったにょろ↓
ttp://software.intel.com/en-us/articles/intel-intrinsics-guide 128 bitリニアのビットシフトとか、128 bitリニアの加減算がやりたかっただけなのだけど、上の一覧表のおかげで作業がはかどり完成すた、
汎用レジスタとのやりとりは、setよりもinsertで(ただし32 bit値を)ぶちこむ方法で、メモリを経由せずに直に高速に値をレジスタ渡しできる
あとはshuffleかunpackで増やしたり移動させたりでくる、
insert/extract命令は発行ポートが1個しかないしレイテンシも大きいので、 場合によってはメモリストアしてロードしたほうがかえって性能出る場合も あるよ。 たとえばの話、レイテンシ3だから同じXMMレジスタに4回insertしたら 合計で12クロックのレイテンシチェインが生じる。 ユニットの空きにもよるけど、 mov(store) 4回+movdqa 1回のほうが短いサイクルですむこともありうる。 ストアデータはバッファリングされるのですぐに呼び出す場合は 比較的短いサイクルですむ。
>>928 説明が端折りましたが現状、だいたい32 bitを1回書くだけで事足りるような使い方ばっかりです…
下位64ビットのMSBの1/0値を上位64ビットに足す例(キャリーの伝搬)↓
z = _mm_setzero_si128(); // これはそのうち不要になる予定
// ...
c = _mm_insert_epi32(c, 0, 0); // R0を0にする。R1のMSBがキャリー
c = _mm_cmplt_ep(c, z); // R1のMSBが1ならR1=0xffffffff, 0なら0x00000000になる。
c = _mm_shuffle_epi32(c, 0x50); // 元R1をR3、R2にコピー、元R0をR1、R0にコピー(下位64 bitは0)
y = _mm_sub_epi(y, c); // 元のcのR1のMSBが1なら-1が引かれる=1加算。
それはそうとして、ようわからんのですが、レイテンシが3だとして、レイテンシ3が連続する限りは
パイプラインのステージの競合が起きず、スループット×命令数、で消費クロックサイクルが済むのでは…(つまり3×4よりは少ない
レイテンシが2から3に変わるとか、不連続部分でライトバックステージの競合が生じたときレイテンシがそのまんま遅延分になる、
というだけなのでは…
なんかこう、うん、まあ、頑張れ 道は長いぞ
原則的には書き込んだ結果を後続の命令で参照するときに依存関係が生じる。 書き込み先が別々のレジスタ、あるいは全書き換えなら依存は発生しない。 部分書き換えだと前の演算結果が確定するまでストールする。
いやそれが>929のcへの繰り返し代入部分を別の中間変数(s、t、rを経由とか)に変えても VC2010において、吐かれるアセンブリコードが全く変わらないっていうか、(xmm0とxmm2しか使われない) もはやインラインアセンブラで手動でレジスタの分散が必須? ていうか、次のコードになるのです… xor eax,eax pxor xmm1,xmm1 // (A) pinsrd xmm2,eax,0 // (B) pcmpgtd xmm1,xmm2 // (C) pshufd xmm1,xmm1,50h // (D) paddq xmm0,xmm1 // (E) 部分書き換えにあたるのは(B)ですが、xmm2が依存する演算は直前2命令より前に開始されているはずなので、 そいつらのレイテンシが3以下なら(B)実行時点で解消済(よって(A)→(B)→(C)でパイプラインストールは生じない)と観て良く無くないです? 同一ステージの衝突を避けるために、1サイクル単位のストールは引き起こされるかもしれないが、 パイプライン全クリアみたいな極端なストールは起きないのでは…
日記帳モードサーセン; Q1: レイテンシの意味がようわからんのですが、パイプラインの段数が20段ぐらいあるとして、 データ入力ステージから(実行ステージを経て)データ出力ステージに至るまでのサイクル数、と見て良いのでしょうか Q2: とすれば、漏れのCPUは06_1Eので、 (A)-(B)間 スループット1 (∵依存関係無し、pxor xmm, xmm スループット0.33) (B)-(C)間 スループット2 (∵依存関係有り、pinsrd xmm, reg, imm レイテンシ2) (C)-(D)間 スループット1 (∵依存関係有り、pcmpgtd xmm, xmm レイテンシ1) (D)-(E)間 スループット1 (∵依存関係有り、pshufd xmm, xmm, imm8 レイテンシ1) ということで、(B)-(C)間以外ではあんまりストールしない、で合ってます? (B)-(C)間で>928の通りになることは理解いたしますた、 Q3: 先行する演算の結果に依存する演算において、ストールはxmmレジスタの全ビットの確定まで続くのでしょうか。 それとも、値が確定したパックからどんどん先行するんでしょうか(shuffleとか)。 普通のアーキテクチャならパイプラインの入り口で命令フェッチ→デコード、という手順を踏むので前者以外あり得ないが、 インテルのやつは命令キャッシュに水平マイクロコードを格納するとか聞いたので、もしかしたら…
Q1. 正解 Q2. > (A)-(B)間 スループット1 (∵依存関係無し、pxor xmm, xmm スループット0.33) 1Eってどれだったっけ? pxorによるゼロクリアで依存関係解消のヒントとして使えるのは Sandy Bridge世代からなので、 それより前に同じレジスタをレイテンシチェインの長い命令で使ってたとしたら それ以前のCPUでは別のレジスタに割り当てたほうが性能が出る可能性はある。 とりあえずそんなに悪いコードには見えないけど、VC++のSSE/AVX関連の最適化 って結構タコだからあてにはしないほうがいいことは間違いない。 Q3. > 先行する演算の結果に依存する演算において、ストールはxmmレジスタの > 全ビットの確定まで続くのでしょうか。 これが正解。 一部だろうが全部だろうが値が確定するまで後続命令は発行できない。
>>934 >pxorによるゼロクリアで依存関係解消のヒントとして使えるのは
>Sandy Bridge世代からなので、
pxorで依存関係解消ができないのはMMX Pentium Proだけ?だと思ってたけど。
Zero Idioms化されたのがSandyじゃなかったっけ?
>>933 Q1について
最適化マニュアルに書いてあるレイテンシとかスループットは基本的に実行ユニットのものだよ。
Q2について
pinsrdはパーシャルアクセスになる命令ではないはず。
レジスタのパーシャルアクセスでもPentium3以前だとレジスタのライトバックまでストールしてたと思うけど
今使われているものは値の確定後に1レイテンシ分のマイクロ命令追加で済んでるはずだと思った。
細かいストールを気にするより、
>>932 がループだとして、C、Eの後に依存性を切るチャンスがあるから
そこで次のサイクル以降の処理が効率よく実行できるようなコードにするのがパフォーマンスを引き出すコツだよ。
数クロック単位の遅れが直接問題になることなんてまずないし。
pinsrdだとシャッフルユニットがボトルネックになりそうだから、AVX2が使えるなら_mm_cvtsi32_si128と_mm_blend_epi32や
AVX2無しならblendの代わりにpandとpor使ってもいいかもね。
936 :
デフォルトの名無しさん :2014/01/13(月) 15:00:28.68
質問です。 GCCだと _mm_mul_ps を __builtin_ia32_mulps に出来て、更に 直接 *(かけ算) でも同じアセンブラに展開されるけど、他にどんな 演算子が実装されているかのドキュメントってどこかにあるもんでしょうか? 演算子を使った方が移植性が高くなるんで、極力使いたいもので。 (他にビット演算が出来そうなのは確認済み)
>演算子を使った方が移植性が高くなるんで、極力使いたいもので。 gccの組み込み関数を使うと移植性が低くなるわけだが ドキュメントはgcc builtin functionsでググれ
>>937 ,938
どうもです。見てみます。
_mm_mul_psの記法はARMのNEONとかには使えないから、出来るだけ四則演算とか
使った方が移植性が高いと思った次第です。
NEONで動かした事がないんで全くの推測ですが…
ああ移植性って異なるISA間での移植性か... SIMD使うなら速度を気にしてるんだろうし、コードパス自体を分けたほうがいいと思うなあ
>>937 のドキュメントを見るとISAに依存してなさそうなshuffleとかもあるし、
比較演算使うとレジスタが-1になるんで、これでselectとかも実装できそう。
完全には無理そうだけどほとんどはISAに依存しない書き方ができそうなんで、
もう少し調べてみます。
環境依存するコードは素直にそれぞれ書くしかない
SIMDをISA間で共通化させるっていうのは無理だし、 現状ですらSSEとAVXも分けて書かないといけないから、 普通にハードウェアチェックをしたあとストラテジー パターンで切り分けるのがいいんじゃないか? そのほうがコードのメンテも楽だし。
調べると言ったんで一応書いておく
外積は以下のように書けた (GCC 4.8.1)
// (A1, A2, A0, A3)
// *
// (B2, B0, B1, B3)
// -
// (A2, A0, A1, A3)
// *
// (B1, B2, B0, B3) ← 外積の定義 (A3,B3は0決め打ち)
__m128i mask1 = { 1, 2, 0, 3 };
__m128i mask2 = { 2, 0, 1, 3 };
__m128 result = __builtin_shuffle(A, mask1)
* __builtin_shuffle(B, mask2)
- __builtin_shuffle(A, mask2)
* __builtin_shuffle(B, mask1));
これでintrinsicで書いた時と全く同一のアセンブラコードが出るのを確認した
>>943 それは、
http://gcc.gnu.org/wiki/FunctionMultiVersioning っていう便利な機能が4.8から入ったよ (まだx86だけっぽいけど)
>>944 はISAに依存した命令は書いてないからNEONでも動きそうな気配はある
ただ全くの未検証
FunctionMultiVersiong便利そうだけど これコンパイル時のフラグはどうしたらいいんだ? SSE4.2有効にしたらversiong指定していない関数もSSE4.2使って最適化コンパイルされてしまうんじゃね
>>946 まだ試してないから何とも言えないけど、1ファイル1関数にすればいいはず。
で、個別に最適化オプションを付けるしかないね。
1ファイル1関数って言い方は変だった。 SSE3とかSSE4とかの各バージョン毎に1ファイルにすればいいかな。
gccに-march=sse2とか渡しても当該の関数だけ-march=sse4.2扱いしてくれるんじゃねえの? 別ファイルに分けるんならこんな機能要らねえじゃん
> 別ファイルに分けるんならこんな機能要らねえじゃん え?何か誤解してないか? 実行時に拡張機能を自動判別して関数をディスパッチしてくれる機能だぞ。 単純に手間を削減してくれる便利機能だと思うけど。 どっちにしろ、実際に試してみないと何とも言えない。
たぶんFunctionSpecificOptと組み合わせろってことだろうけど intrinとかのヘッダーファイル読むときにmsse*ついてないと読めない気がしたんだよな
結局関数ポインタで切り替えるわけだから、gccのリンカじゃインライン展開してくれないだろうな。
AVX2命令使うとi7がチンチンに熱くなるんだけど 消費電力大きいのか?
SSE利用時と比べて電圧が上がるんじゃなかったっけ
AVX2命令使うとチンチンが熱くなるんですが どうしたらいいですか?
そのAVX2命令の能力で高速に描画される動画を見て抜いてすっきりしなさい。
俺もHaswell i7を尼でポチったからIntelから久しぶりに命令PDFでも落とすか SSE2しか使ってなかったわ
ML64.exeなんか勉強しないといけないな めんどくさ('A`)
AVX2は256bitを常に満たしつつ演算していかないと電力効率が悪そうだな。 ゲーム系の場合はSSE命令(intrinsic)をコンパイラが依存関係を調べて 自動的にAVX命令に変換してもらわないと、手作業で256bitを埋めるのは しんどいだろう。
内積の計算するのにSSE3から追加された_mm_hadd_psを使うより、以前の 3回_mm_shuffle_psしてから足すやつの方が速かった…(corei7) SSE3はいらない子だったんだな、残念 しかしCPUはAVX2まで対応してるが、脳ミソをSSE4以降に対応させるのはしんどい…
AVX2もたいして速くないね。 単にできるようになっただけ。
>>960 内積演算するのになぜdppsを使わないの?
こっちも大して速くないけど。
ぶっちゃけると
struct { float X, float Y, float Z }ならX[8], Y[8], Z*[8]にパックしなおして
処理が終わったときに戻すようにすればいい。
そしたらvfmulps + vfmadd231ps + vfmadd231psの3命令で8並列処理できる。
>>962 > 内積演算するのになぜdppsを使わないの?
dppsはSSE4の命令でまだ普及率を考えるとSSE2でいいやと思っただけ
> struct { float X, float Y, float Z }ならX[8], Y[8], Z*[8]にパックしなおして
それはAOS→SOAにしろって事だけど内積だけを8個以上のベクトルに適用する事がないな
大量の頂点をCPUで座標変換する時には間違いなくそうすべきだけど普通GPUでやる訳だし
> dppsはSSE4の命令でまだ普及率を考えるとSSE2でいいやと思っただけ SSE4対応のCPU普及率が低いなんて統計あったっけ? 複数バージョンの関数作ってCPUID見て分岐すりゃいいじゃん。 そこで妥協したら何のためにSIMD命令をわざわざ使ってるのという話になる > それはAOS→SOAにしろって事だけど内積だけを8個以上のベクトルに適用する事がないな 別に内積「だけ」をSoAで処理してそれ以外をAoSで処理しなければならないなんて ルールを作る必要ないよ。
まーた都合のいい解釈が始まった
>AOS→SOA C++でオブジェクト指向でプログラム作ってるのに こんな真似しなきゃならんとは
>>967 SIMDを使うということは、低レベルのプログラミングになるのは当たり前。
オブジェクト指向ならストラテジでSIMDの詳細コードを書けばいいだけ。
dppsよりmulps,addpsしたほうが速いからな
以前ある処理をSIMD/マルチスレッドで高速化したことがあったが、同じ処理を OpenCLで書いたらプログラムが格段に簡単になった上にさらに数10%速くなった。 イマドキのコンパイラに素人が挑んでも敵わんと実感したわ。
OpenCLはCPUのコードでも速くなるのか。 ひょっとしてSIMD化までやってくれるのか??
普通にやってくれる。もともとOpenCLはSIMD前提の規格だし、相性は悪くないんだろう。 あと、実行時にコンパイルするから実行環境に合わせた最適化ができるってのも大きいんだろうな。
973 :
971 :2014/02/01(土) 10:53:59.16
うお、AVX2とかも実行時コンパイルできるわけか! 今まではイントリンシックでのSIMD化が、コードの複雑さとパフォーマンスの最適点だと思ってたけど、 OpenCLがそこまでできるなら話が違ってくるな。 ちょっと触ってみるわ。
選択肢は多数あるよな。 C++ AMPのサンプルなんて、CPU_C++ノーマルとCPU_AMP最適化では 21倍の差が出たよ。
975 :
971 :2014/02/01(土) 14:01:59.27
うん、GPU使うならC++AMPがいいな。 C++11の範囲内だけで書けるし、パフォもなかなか。
OpenCLって文字列でコード埋め込むクソ仕様だろ
そんな事言ったらOpenGLだってシェーダーは文字列でコードに埋め込む糞仕様だよ 普通は適当に暗号化してバイナリにくっつけてると思うが
>dppsはSSE4の命令でまだ普及率を考えるとSSE2でいいやと思っただけ SSE4.1って45nm Core2で使えるようになったと思ったから 5年以上たってると思うけど
>>973 いまのOpenCLでCPUのコードが自前でSIMD化したものより速いんだったら、
SIMDのコードが糞だと思うよ。単純なベクトル化だけだったらインテル
コンパイラを使ったほうが幸せになれる。
>>979 自動ベクタ化ではインテルの圧勝だけど、intrinsicsで書いてあればVCとほぼ互角な気がする
インテルが負けることも多いなぁ
>>980 インテルコンパイラがVCと互角になるようなことって、
同じ条件で、計算でボトルネックになるところではは
ないと思うけどな。
>>981 intrinsicsのSIMDコードが処理時間の多くを占めているので、
命令のスケジューリングではほぼ互角といってもいいと思います
プログラマがSIMDの世話さえしてやれば、あとはVC++のコンパイラでも十分高速だと思うなぁ。 さすがにIntelプロセッサでIntelコンパイラには敵わないだろうけど、それでも差は1、2割とかじゃないの??
>>979 ちなみにCPUで使えるOpenCL環境にはIntel製とAMD製があって、Intel CPUで動かした場合は
倍くらい性能が違った。
それぞれ自社のCPUに特化しているというのもあるんだろうが、やっぱりインテルのコンパイラは
この分野では優秀なんだろうな。
intrinsicsで書かれたコードなのでレジスタのアロケーションと命令のスケジューリング の比較と言っていいと思うけど、VCが勝つこともあるし差も僅かなのでほぼ互角としました OpenCLは一応ベクタ化の工程があるからインテル製が強いんじゃないかなぁ NECと提携してコンパイラの技術も向上してるのかな?
あれは内部的にはSoAに変換して処理してる。 命令セット側が並列化用の高級言語に歩み寄ってる面もあるよ AVXにはvblendvpsとかのプレディケート命令もあるしvgatherやvpermilpsで 効率的にAoS-SoA変換を行うことができる。 その辺の仕組みがわかった上で使う分にはいいよ AVX-512ではSIMDレジスタが32本と8本(7本)マスクレジスタ 主要命令がプレディケーション対応になるからますます並列化言語が有利になる 少なくともこれからの時代は 「最新命令についてけないバカと老害にはSIMD化コードを触らせるな」 とはいえるかもしれない。 OpenCLで書かれたコードは実行時コンパイルだからランタイムさえ更新されれば 最新命令に追従できるからな。
プレディケーションサポートはうれしいな。 今までガリガリ自分で書いてた。
団子ちゃん今は派遣じゃないんだっけ?
わざわざ「触らせるな」と言わんでも、素のSIMDコードを書くのはこの先 コンパイラ屋と組み込み屋と物好きだけになっていくだろうな。
馬鹿に触らせるななんて プログラムに限らず大昔からだよ
戦時にもあったっけな 勤勉なバカが一番害悪だとか
真面目系クズみたいなもんか
ゼークト将軍ね。
>>989 あと数値計算だな。
もっとも最近はGPUとかで、SIMDのコードすら書かなくなってきているけど。
コンパイラが進歩してきてるから、数値計算やりたいだけの人は SSEのような素のSIMDを扱う必要はなくなるって話だろ。
SSE系SIMD拡張は、コンパイラの対応がクソすぎた ヒープをアラインしたきゃ_aligned_malloc使えとか 自動ベクトル化〜♪とか 早くHSAとかに駆逐されるべき
GPGPUはお膳立てがもっと面倒だぞ
999 :
デフォルトの名無しさん :2014/02/10(月) 00:11:11.34
埋めましておめでとうございます!!!
SIMDは永久に不滅です!
1001 :
1001 :
Over 1000 Thread このスレッドは1000を超えました。 もう書けないので、新しいスレッドを立ててくださいです。。。