[表示 : 全て 最新50 1-99 101- 201- 301- 401- 501- 601- 701- 801- 2chのread.cgiへ]
Update time : 05/23 20:39 / Filesize : 188 KB / Number-of Response : 807
[このスレッドの書き込みを削除する]
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧] [類似スレッド一覧]


↑キャッシュ検索、類似スレ動作を修正しました、ご迷惑をお掛けしました

【C++】高速化手法【SSE】



1 名前:デフォルトの名無しさん mailto:sage [2005/10/27(木) 02:55:36 ]
C++やインラインアセンブラ、SSEなどによる高速化の手法
について語りましょう。

654 名前:デフォルトの名無しさん mailto:sage [2011/10/10(月) 19:56:01.06 ]
>>652
あっちはCでだから。
>>653
使う方がスカラーなのよ。

655 名前:デフォルトの名無しさん [2011/10/11(火) 20:37:34.29 ]
>>2
これっていまでのそうなの?

656 名前:デフォルトの名無しさん mailto:sage [2011/10/11(火) 21:19:20.86 ]
>>655
お前はQuickCでも使ってろよ

657 名前:デフォルトの名無しさん mailto:sage [2011/10/13(木) 04:16:06.44 ]
なんで PSLLB だけないんだろう?

658 名前:デフォルトの名無しさん [2011/11/05(土) 00:09:14.57 ]
x64の組み込み命令で、xmmレジスタに定数を代入したいんですが
__m128i xmm0;
xmm0.m128i_u64[0] = 0x1212121212121212;
xmm0.m128i_u64[1] = 0x1212121212121212;
これより速い方法はありますか?
各バイトが必ず同じ数字になるとして

659 名前: ◆0uxK91AxII mailto:sage [2011/11/05(土) 00:32:10.02 ]
>>658
定数はループの外で置きっぱなしにするし、x64だとレジスタが多いから、そのままで良いと思ってみる。

mov eax, 12121212H
movd xmm0, eax
pshufd xmm0, xmm0, 000H

660 名前:デフォルトの名無しさん mailto:sage [2011/11/05(土) 08:34:55.68 ]
VC++だと
__m128i xmm0 = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12};
でmovdqaを使うようになる

661 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/11/11(金) 03:05:16.98 ]
VC++だとそれでいいけどGCCだとコンパイル通らなかったりするんだよね。
最適化ルーチンが腐ってなければ大体これでいけるけど。
__m128i xmm0 = _mm_set1_epi8(0x12);

というかアセンブリ出力読むと良いよ。

662 名前:デフォルトの名無しさん mailto:sage [2011/11/28(月) 22:54:57.76 ]
>>654
お前はスクルトでもツカッテロ



663 名前:デフォルトの名無しさん mailto:sage [2011/11/28(月) 23:12:10.08 ]
スクカジャの方が良いよ

664 名前:デフォルトの名無しさん mailto:sage [2011/12/17(土) 22:41:12.80 ]
signed shortの配列に
floatもしくはdouble型の乗算をして
クリップ処理をほどこし
signed shortの配列に戻すのを
SSEにしたいのでやってください


これ

signed short s[100];
float f
init a;

for (a=0;a<100;a++)
s = s[a] * f;

665 名前:デフォルトの名無しさん mailto:sage [2011/12/17(土) 23:06:34.33 ]
それ、どう考えても実数型⇔整数型のコストがでかすぎる。
たった100件でいいなら実数で持てないの?

666 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 00:38:02.93 ]
>>665
100は例で実際はは数千万程度
waveファイルPCMの加工で

667 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 01:11:33.16 ]
>>664
自分で学習しないと答えを聞いても使えんよ。
そもそも意味不明なコード書かれても誰も答えられない。

668 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 01:24:45.87 ]
>>667
ワカンネーならクチダスな

669 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 01:28:37.19 ]
#1:すぐに話の風呂敷を広げる
#2:よく理解しないまま突っ走る
#3:嫌われていると勝手に思い込んでいる
#4:キレて他人に八つ当たりする
#5:やたらと自分の正当性を主張する
#6:何も自分で決めない
#7:何かにつけて理屈をこねる
#8:やたら褒めてほしがる
#9:他人の話を聞かない
#10:何が言いたいのかわからない
japan.zdnet.com/sp/feature/07tenthings/story/0,3800082984,20421237-2,00.htm

670 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 01:29:57.57 ]
自分語り 乙w

671 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 03:08:00.84 ]
s = s[a] * f; って何がしたいんだw


672 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 04:36:52.55 ]
話の内容を察するに、s[a] *= f; ってことだとおもうけれど



673 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 15:35:15.11 ]
それじゃ飽和処理してないし

674 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 15:54:06.36 ]
つーか、コンパイル通るの?

675 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 17:04:56.31 ]
何も書いて無いけどどうせ色々特殊処理もあるんだろうから、予め
0x0000-0xffffに対する結果を128K byteのテーブルに計算しておき、
後はテーブルルックアップすれば良いだろw

676 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 18:08:27.37 ]
いっそ0x0000-0xffffffffに対する結果を16GByteのテーブルに(ry

677 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 18:58:44.22 ]
>>666
音を大きくしたり小さくしたりしたいだけなら、0.0〜1.0を、0〜255 とか 0〜65535 とかにして、
整数演算に帰結させてMMXのほうが速いんじゃ…

678 名前:デフォルトの名無しさん mailto:sage [2011/12/18(日) 23:16:56.16 ]
お前らやさしいな

679 名前:デフォルトの名無しさん mailto:sage [2011/12/19(月) 02:15:44.43 ]
初めてSSEに触れるので、まずは簡単なコードを作成してみたのですが、
SSEを使わないほうが40倍も速いという驚愕の結果が出ました。
何が間違っているんでしょうか??

コンパイラ:VC++2005(Releaseモード、浮動小数点モデル:FAST)

float* f4pakAdd( float* pfA, float* pfB )
{
  _declspec( align( 16 ) ) static float fC[ 4 ];
  
  _asm
  {
    mov ebx, pfA
    movaps xmm0, oword ptr [ebx]
    mov ebx, pfB
    movaps xmm1, oword ptr [ebx]
    addps xmm0, xmm1
    movaps fC, xmm0
  }
  
  return fC;
}

呼び出し側

for( int i = 0; i < 10000000; i++ )
{
  pfC = f4pakAdd( fA, fB );
}

680 名前:679 mailto:sage [2011/12/19(月) 02:15:55.13 ]
_asmのスコープをコメントアウトして、以下のようにスカラの加算を並べたほうが40倍速くなりました。

fC[ 0 ] = pfA[ 0 ] + pfB[ 0 ];
fC[ 1 ] = pfA[ 1 ] + pfB[ 1 ];
fC[ 2 ] = pfA[ 2 ] + pfB[ 2 ];
fC[ 3 ] = pfA[ 3 ] + pfB[ 3 ];

681 名前:679 mailto:sage [2011/12/19(月) 02:17:15.89 ]
fA、fBは以下のように宣言しています。

_declspec( align( 16 ) ) float fA[ 4 ] = { 1.0f, 2.0f, 3.0f, 4.0f };
_declspec( align( 16 ) ) float fB[ 4 ] = { 5.0f, 6.0f, 7.0f, 8.0f };

682 名前:デフォルトの名無しさん mailto:sage [2011/12/19(月) 02:34:54.14 ]
パイプライン化したコードでもないし、スタックチェックが行われている気がするが。
逆アセ確認したかい?



683 名前:デフォルトの名無しさん mailto:sage [2011/12/19(月) 02:52:57.82 ]
40倍も遅いというのはインライン展開されずに普通に関数呼び出しされちゃってるんじゃないの

684 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/19(月) 02:58:55.10 ]
インラインアセンブリは関数のインライン展開を阻害するから
どうしてもASMを使いたいとか宗教的な理由が無い限りintrinsicsを使うべき

強いて関数呼び出しにするなら__fastcallにするかな。

685 名前:679 mailto:sage [2011/12/19(月) 02:59:52.23 ]
>>682
逆アセしてみました。

■SSE使用

mov ebx, pfA
004115DE mov ebx,dword ptr [pfA]
movaps xmm0, oword ptr [ebx]
004115E1 movaps xmm0,xmmword ptr [ebx]
mov ebx, pfB
004115E4 mov ebx,dword ptr [pfB]
movaps xmm1, oword ptr [ebx]
004115E7 movaps xmm1,xmmword ptr [ebx]
addps xmm0, xmm1
004115EA addps xmm0,xmm1
movaps fC, xmm0
004115ED movaps xmmword ptr [fC (417540h)],xmm0

■SSE未使用

fC[ 0 ] = pfA[ 0 ] + pfB[ 0 ];
004115DE mov eax,dword ptr [pfA]
004115E1 fld dword ptr [eax]
004115E3 mov ecx,dword ptr [pfB]
004115E6 fadd dword ptr [ecx]
004115E8 fstp dword ptr [fC (417540h)]

配列インデックス1以降も同じ感じです。

どちらもまじめに演算しているだけのようですね・・・

686 名前:679 mailto:sage [2011/12/19(月) 03:16:03.78 ]
すみません、>>685はDebugモードでの逆アセで、Releaseモードでは以下のように
インライン展開されていました。
先ほどのはどちらも関数呼び出しを行っていました。(お決まりのpushやret)

■SSE使用

for( int i = 0; i < 10000000; i++ )
{
pfC = f4pakAdd( fA, fB );
004011A6 lea ecx,[esp+10h]
004011AA lea edx,[esp+30h]
004011AE mov dword ptr [esp+28h],ecx
004011B2 mov dword ptr [esp+2Ch],edx
004011B6 mov eax,989680h
004011BB jmp WinMain+190h (4011C0h)
004011BD lea ecx,[ecx]
004011C0 mov ebx,dword ptr [esp+2Ch]
004011C4 movaps xmm0,xmmword ptr [ebx]
004011C7 mov ebx,dword ptr [esp+28h]
004011CB movaps xmm1,xmmword ptr [ebx]
004011CE addps xmm0,xmm1
004011D1 movaps xmmword ptr [__fmode+10h (403380h)],xmm0
004011D8 sub eax,1
004011DB jne WinMain+190h (4011C0h)
}

687 名前:679 mailto:sage [2011/12/19(月) 03:17:00.05 ]

■SSE未使用

for( int i = 0; i < 10000000; i++ )
{
pfC = f4pakAdd( fA, fB );
0040114A fld dword ptr [__real@40c00000 (40213Ch)]
}

これって、定数演算だから、事前に計算した結果をメモリに置いておいて、
ロードするだけってオチでしょうか・・・(汗ンブラ)

688 名前:デフォルトの名無しさん mailto:sage [2011/12/19(月) 03:18:45.19 ]
SSEなんてたいして効果無いんだろ。
コンパイラまかせでいい。
小手先のテクより、アルゴリズムやGPU使用など劇的変化が見込める所を研究すべき。
SSEは最高が20%とかだろ。

689 名前:679 mailto:sage [2011/12/19(月) 03:19:44.86 ]
>>683
Debugモードではいずれも関数呼び出しありで、
Releaseモードではいずれもインライン展開されていました。
両モードでこういった差があることは意識していなかったので勉強になりました。

>>684
団子さん、ありがとうございます。
今回は勉強の一環としてアセンブラを使いましたが、
できるだけ組み込み関数を使うことにします。
(__fastcallにしたら速度が半分に低下してしまいました・・・)

690 名前:デフォルトの名無しさん mailto:sage [2011/12/19(月) 03:31:49.83 ]
実用上はインライン展開で速くなることは稀。
関数にするからには一カ所より多くの所からコールされる可能性が高く、
インラインにしなければCPUキャッシュに乗っている場合に関数を使い回しができて高速化される。

691 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/19(月) 03:36:24.22 ]
変数をスタックに積むのって結構無駄だろ?
呼び出し元の関数が小さい場合は特にね。

VC++の32ビット版の場合、__fastcall規約だとxmmレジスタで3つまで渡せるよ。

692 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/19(月) 22:10:00.23 ]
失礼
VC++だと__m128{,i,d}は呼び出し規約にかかわらずレジスタ渡しになるね
てかレジスタ渡し以外不可能。
ちなみにgcc(Linuxなど)とかだといったんストアしてポインタ渡しになる。



693 名前:デフォルトの名無しさん mailto:sage [2011/12/20(火) 02:40:46.25 ]
>>692
なんか昔より太ってね?

694 名前:デフォルトの名無しさん mailto:sage [2011/12/20(火) 02:51:35.79 ]
なりすましとか勘弁してください

695 名前:デフォルトの名無しさん mailto:sage [2011/12/22(木) 08:12:33.37 ]
>>690
今の時代のインライン展開って、call命令減らすというより、コンパイラの最適化効きやすくするためというほうが大きいんじゃない?
うまくいけば数命令ぐらい減るし。

696 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/22(木) 22:22:40.93 ]
ステップ数の少ない小さい関数限定だな

697 名前:デフォルトの名無しさん mailto:sage [2011/12/22(木) 23:47:29.24 ]
C++の話なら、たんなる要求に過ぎないので、
ステップ数が大きければコンパイラがinline指定を無視するような気もするな。


698 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 01:18:10.46 ]
gettimeofday()してusecを返すだけの関数はインライン展開したけれど、
(sec%1000)*1000*1000を足したら関数呼び出しになった(gcc4)。

699 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 01:49:52.05 ]
>>698
1関数呼び出しのみの関数はエイリアスとみなしてるんじゃね?

後者は引数渡しのオーバヘッドが無いし、インライン展開のメリットがあるか微妙な線だな。


700 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/23(金) 01:52:20.02 ]
おいらC++の場合だとそれほど大きくないクラスならヘッダ内に関数実装も含めて書いちゃうし
最適化時にどれがどう展開されるかはコンパイラ任せという罠。

701 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 04:20:10.94 ]
インラインやマクロは最初から使わない方が良い。
EXEでかくなり、メモリ使用量も増える。
自分はオプションでインライン展開しない設定にしてる。
それで実測してみて、関数コールが実際に負荷になっていれば書き換えれば良い。
しかしそんなことが有ったことがない。
速いという思い込みでインライン指定してるだけとおもう。

702 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 06:03:00.08 ]
templateなんか駆使すると
インライン展開されないと
桁違いに遅くなるけど



703 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 09:45:11.17 ]
maxとかabsとかSSE一命令でいけるのにわざわざレジスタ退避してcallしてたら
コードサイズもでかくなるしいいことないだろ

関数のサイズをちょっとずつ大きくしてくとわかるけど
インライン展開の閾値を超えた瞬間にインラインで展開されてた数命令規模の関数が
一気にcallに置き換えられてサイズが爆発するから

704 名前: ◆0uxK91AxII mailto:sage [2011/12/23(金) 09:52:16.15 ]
mapとか、コンテナにvoid *を突っ込む癖が付いてしまう。

705 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 09:54:07.89 ]
C++は面罵関数がインライン展開されなかったら話にならないからな。

自分はオプションでインライン展開を積極的に行なう設定にしている。
それで実測してみて、EXEの大きさやメモリ使用量が実際に問題になっていれば書き換えればいい。
しかしそんなことがあったことがない。
増えると言う思い込みでインライン設定を毛嫌いしているだけだと思う。

実際、ベクタ化の方がよっぽどコードサイズが増えるよ。

706 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 09:55:04.79 ]
あと、SSEの場合アラインメントの推論が切れるのがかなり問題で

関数単位でコンパイラが見てしまうと
ポインタにはアラインメントの情報が乗っていないから
iccなんかは気を利かせて一旦アラインメントされたスタック上にコピーする
コードを挿入してしまったりする
アラインメントされてないとペナルティが大きいからね

インライン展開されると
アラインメントされているスタック上の変数や
明示的な_mm_load_psなんかから
変数やポインタのアラインメントを推論するので
アラインメント前提のコードを生成させることができる

707 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 11:26:47.88 ]
どんな変数も問答無用でアライメント16にするようにコンパイルする設定があれば
面倒な記述を減らせると思うんですが、何かデメリットあるんでしょうか?
メモリの隙間ができて勿体無いとかあるかもしれませんが、メモリ量の多い昨今、
それほど問題にならないのでは?と思います。
むしろアライメントすることでメモリアクセスの冗長さを減らせて帯域を節約する効果も
あって一石二鳥ではと思うんです。

708 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 11:59:03.43 ]
gccだと-mpreferred-stack-boundary=4がデフォルトだから既に16バイトアライメントだよ
構造体の詰め物は互換性もあるし難しいじゃないか

709 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 12:28:16.46 ]
>>707
互換性

710 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2011/12/23(金) 12:41:37.02 ]
>>707
なにそれ君いまだにPS3向けのゲームとか組まされてるわけ?

711 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 15:57:24.48 ]
>>708
glibcのmallocは8バイトだよ

>>710
SandyBridgeでもアラインメント取れてないと遅いでしょ

712 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 16:00:51.42 ]
構造体はCの規格だと順番を入れ替えられないだけで詰め物はし放題だよ
実際4バイトアラインメントのアーキテクチャだとコンパイラが詰め物するでしょ



713 名前:デフォルトの名無しさん mailto:sage [2011/12/23(金) 17:19:17.60 ]
>>711
Nehalem以降はmovups/dquもペナルティ無く使えるでしょ
まあ結局Core2以前も考慮するとコード振り分けるから労力は変わらないのだけれど...

714 名前:707 mailto:sage [2011/12/24(土) 02:12:26.59 ]
すみません、自分は日曜プログラマレベルで、対象CPUはx86、環境はVC++です。
VC++の設定を見ていると、「構造体メンバのアライメント」というのがあって16バイトアライメントを選べるようになってました。
同様に通常の変数もアライメントできる設定があるかと思い探しましたが見付かりませんでした。

715 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 02:18:17.32 ]
どう考えてもこれ以上削れないってくらいの手書きインラインアセンブリコードに対し、
C記述版をVC++のReleaseモード(最適化O2)でコンパイルしたもののほうが1.3倍速かったです。
生成されたアセンブリを覗いてみたところ、

変数 * 3

というコードを

lea edx, DWORD PTR [eax+eax*2]

としていてびっくりしました。
これって、アドレス演算を行うローダ(専用の演算器?)を使うことで、
通常のALUと並行して演算(スーパースカラって言うんでしたっけ?)し
高速化しているということなんでしょうか??

716 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 02:34:46.72 ]
>>714
__declspec(align(N))

717 名前:707 mailto:sage [2011/12/24(土) 02:44:05.59 ]
>>716
ありがとうございます。
それは知っているんですが、>>707でも書いた通り、
そういった記述をわざわざせずとも、自動で全てアライメントしてくれるような設定があればイイのでは?
と思った次第です。

しかし、上でも仰られたように、互換性の問題があったりで難しいのでしょうね・・・
でも二重インクルード防止の「#pragma once」のように、互換性を考慮しない機能があったりするくらいですから、
自分のようにずっとVC++しか使わない人間を対象にそういうオプションが用意されていても良いのではと思いました。

718 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 04:29:51.40 ]
>>715
ついでにPartial flags stallも回避できるな

719 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 05:22:08.10 ]
>>717
キャッシュミスが多くなったら速くならない。
だから隙間が多すぎるのは良くない。

まだそのレベルの高速化を気にするレベルじゃないと思うが、気になるなら続きは↓とかで。
toro.2ch.net/test/read.cgi/tech/1322981274/
toro.2ch.net/test/read.cgi/tech/1302223650/

720 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 06:03:11.07 ]
>>713
Nehalemでmovupsのペナルティがなくなったのはアラインメントされている場合だけ
Penrynまではアラインメントされていてもmovapsより遅かった
ハードウェアがどういう実装になっているのかをよく考えてほしい

さらにSandyBridgeでは非アラインメントの場合
2つあるロードユニットが生かされないばかりか追加ペナルティもあるので
アラインメントされている場合に比べて非常に性能が落ちる

movaps/movups使い分けの時代はSegmentation Faultの温床だったので
movupsオンリーで書ける様になったのはうれしいよね

Haswellで32Byteアラインメントが出てくるかと思うと頭が痛いが

721 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 06:12:36.27 ]
>>716
VCの__declspec(align(N)) や gccの__attribute__ ((aligned(N)))は
スタックやベースポインタからのアラインメントは保証されるけど
ヒープにどう確保されるかは保証されないよ
ランタイムライブラリ依存だからね

そのクラスのnew/deleteをオーバーロードするか
大雑把にグローバルでオーバーロードするかしないといけないが
どちらも一長一短ある

722 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 08:19:59.68 ]
>>717
ぶっちゃけそれやってどれだけの速度向上が望めるの?って事情もあるんじゃねーの
たかだか1MBに満たないスタックに、って
最近のCPUだとunalignedアクセスの性能低下も軽減されて古いCPUだと速くなるって言われてもなーって気持ちもあると思う



723 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 08:56:50.23 ]
SandyBridgeもL1D$は1R1Wの4bank構成で
うまくバンクコンフリクトを避けないとペナルティがある
非アラインメントのmovupsは2bank使ってしまう

724 名前:デフォルトの名無しさん mailto:sage [2011/12/24(土) 12:22:00.92 ]
>>715
手書きでもふつーにやる。

725 名前:715 mailto:sage [2011/12/24(土) 14:11:41.35 ]
>>718
おお、そんなメリットもあるんですね。

>>724
覚えておきます。

コンパイラの吐くアセンブラを見てると眩暈がしてきましたw
SIMDやプリフェッチ等のキャッシュ制御を除けば、
手書きでアセンブリ書くのはほとんど効果的でないような気がしてきました。

726 名前:707 mailto:sage [2011/12/24(土) 14:22:27.84 ]
>>719
なるほど、バイト境界を跨いでしまってアクセス回数が増えることより、
キャッシュに収まって低レイテンシでアクセスし易くなる効能のほうが上回るわけですね。
いかに外部DRAMへのアクセスがコストになっているかがよく分かります。
あと、スレ誘導もありがとうございます。

>>722
>最近のCPUだとunalignedアクセスの性能低下も軽減されて
そうだったんですか。
それだったらmovupsでいいですね。
でも>>723さんの御意見も気になりますので、パフォーマンス測りながら追い込むようにします。

727 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 00:59:58.08 ]
>>720
64ビットだと、当初MMXが使えなくなるとか言ってた関係で
VCはMMX用の組み込み関数が使えないんだよなぁ
でもって、MMXをSSE2に書き換えるとメモリオペランドのアライメントで
例外が発生したりするんだorz


728 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 01:14:13.06 ]
もう最初から全部、256バイト境界にアライメント揃えて実行ファイル作っとくかw


729 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 04:02:17.42 ]
グローバルのnewをオーバーロードしたくなる時は結構ある

730 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 09:57:01.67 ]
32bitOSを切り捨てたい時もよくある

731 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 11:53:57.38 ]
intやポインタが64bitになっても面倒なだけだと思うけどな。

732 名前:デフォルトの名無しさん mailto:sage [2012/01/10(火) 13:24:45.38 ]
お前がそう思うんならそうなんだろう
お前ん中ではな



733 名前:デフォルトの名無しさん mailto:sage [2012/03/09(金) 12:53:25.77 ]
unsigned int maxpos(unsigned int src[256])
{
unsigned int i, m = 0;
for(i = 1; i < 256; i++)if(src[m] < src[i])m = i;
return m;
}
これをSSEで高速化する方法があれば教えて下さい

734 名前:デフォルトの名無しさん mailto:sage [2012/03/09(金) 14:27:48.76 ]
byte配列ならPHMINPOSUWで速くなりそうだけど、そのコード基本的に検索だからSSE向きではないな。
最大値求めて、それを検索して位置返すのもありだが、速いかは知らんw

735 名前:デフォルトの名無しさん mailto:sage [2012/03/09(金) 15:23:00.43 ]
>>733
src[m]をキャッシュした方が速いと思う。
要は、SSE以前にやることやってからにしろ。

736 名前:デフォルトの名無しさん mailto:sage [2012/03/09(金) 17:16:54.28 ]
unsigned intだとSSE4使わないと素で書いたより無駄に遅くなりそうなのしか思いつかないわ

737 名前:デフォルトの名無しさん mailto:sage [2012/03/10(土) 14:03:19.33 ]
SSE使った方が遅くなるのは何故でつか?

738 名前:デフォルトの名無しさん mailto:sage [2012/03/10(土) 18:35:29.43 ]
日本の道路をF1で走るようなもんだから

739 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 00:41:15.69 ]
>>733
画像とか統計の基礎だな。疑似コードで書くとこんな感じだ

maxpos(src[256]) {
pos = {0, 1, 2, 3};
for(i=0; i<256; i+=4) {
 s=load(&src[i]);
 isGT=maxVal<s;
 maxVal=isGT&s | ~isGT&maxVal;
 maxPos=isGT&pos | ~isGT&maxPos;
 pos += 4;
}
return max_position(
 maxVal[0], maxPos[0],
 maxVal[1], maxPos[1],
 maxVal[2], maxPos[2],
 maxVal[3], maxPos[3]);
}

740 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 01:57:27.28 ]
>>739
SSEは max命令とunpackv命令があるんだから
32bitのsrc[i]値を64bitのsrc[i]<<32|iに変換して最大値を求める方が速いと思うね

741 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 02:00:06.23 ]
740だが、64bitのmax命令はないんだな それなら >>739でいいと思う
スカラーコードより速く
すまん

742 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 12:51:45.57 ]
>>739
signedの比較命令しかないからダメじゃない?



743 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 13:56:40.66 ]
なんか知らんが、そんなのずらせば済む事だろ

744 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 15:40:49.12 ]
実際にコード書いて検証しようぜ。
思い込みと現実は違う場合が結構あるしさ。

745 名前:デフォルトの名無しさん mailto:sage [2012/03/11(日) 16:00:05.53 ]
古いPCを使ってるからかもしれんが>>733を単純にアンロールしたのが一番速いな

746 名前:デフォルトの名無しさん mailto:sage [2012/03/12(月) 00:37:37.24 ]
スレチではあるが、このコードを高速化する必要がある処理を見てみたい気がした。

747 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2012/03/12(月) 04:51:41.06 ]
>>742
0x80000000を引く。
足してもいいしXORでもいいけど。

748 名前:デフォルトの名無しさん mailto:sage [2012/03/12(月) 19:18:44.41 ]
横レスだけどおおすげー。
そもそも正数同士・負数同士の比較ならsigned/unsignedで結果は変わらないので
問題は正数と負数の比較のみ。確かに最上位ビットを反転させれば万事うまくいくね。

749 名前:デフォルトの名無しさん mailto:sage [2012/03/12(月) 19:42:04.67 ]
256個ぐらいだと、最大値を見つけて最大値と同じのを見つけるのだと遅いかな

750 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 01:41:38.96 ]
signedとunsignedの変換が凄いのか。
この手のテクをまとめようと思ったらどのレベルから書いていいか分からんな。

751 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 02:23:57.53 ]
>>749
俺は実装が面倒という理由でそれでやってるが
やっぱメモリに2週アクセスするから遅いのでは


752 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 05:34:13.85 ]
pxor x2+pcmpgtbとpblendvbで最大値のインデックスを保存
インデックスは0x01010101でインクリメント
最後に4要素を比較

4要素あたり2サイクルで回るかな
signed intだったら4要素あたり1サイクルでいけるかも?

unsignedでもcharだとpsub+pblendvbだけでいけるからよいんだけどね



753 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 05:36:23.52 ]
あpmaxudも必要か

754 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 05:54:27.09 ]
__m128i pos = _mm_setzero_si128();
__m128i maxpos = _mm_setzero_si128();
__m128i maxsrc = _mm_set1_epi32( 0x80000000 );
#pragma unroll(16)
for( int i = 0; i < 256; i+=4 )
{
__m128i signed_src = _mm_xor_si128(
_mm_load_si128( (__m128i*)&src[i] ),
_mm_set1_epi32( 0x80000000 ) );
__m128i mask = _mm_cmpgt_epi32( signed_src, maxsrc );
maxpos = _mm_blendv_epi8( pos, maxpos, mask );
maxsrc = _mm_max_epi32( maxsrc, signed_src );
pos = _mm_add_epi32( pos, _mm_set1_epi32( 1 ) );
}
以下略
実行してないのであってるかは知らん

755 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2012/03/13(火) 12:31:21.86 ]
> unsignedでもcharだとpsub+pblendvbだけでいけるからよいんだけどね

その程度ならpacked floatにキャストしてblendvpsでもいけるけどね。

SSE4対応以前ならpmovmskb/maskmovps+test+jccでもいけるか
(メディアンならともかく最大値ならcmovより分岐のほうが速いはず)

756 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 14:51:08.23 ]
>>755
pbledvbは7+8nのビットしか読まないから符号の判定に使える

SSE4以前だとmaskにはand+andnot+orが使われてたね

757 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 14:52:50.84 ]
Penrynだと下手にblendv系使うより速い場合もあったりした

758 名前:デフォルトの名無しさん mailto:sage [2012/03/13(火) 14:59:06.94 ]
ごめんblendvpsも31+32nビットしか読まないのか
勘違いしてた
符号の判定に使えるね

759 名前:デフォルトの名無しさん mailto:sage [2012/03/14(水) 00:38:46.60 ]
>>757
PenrynのPBLENDVBはレイテンシ1、スループット2で
SandyBridgeはレイテンシ2、スループット1か…

Penrynはデコーダの制限もありそうだし、and,orでもよさげ

760 名前:デフォルトの名無しさん mailto:sage [2012/03/14(水) 00:46:50.97 ]
HTが使えるCPUならblendの方がいいかな?

761 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2012/03/14(水) 07:19:23.65 ]
どうせ全検索するんだしレイテンシの長さ分だけインタリーブすればレイテンシ隠せるよ

762 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2012/03/14(水) 07:23:58.09 ]
packed unsigned intの比較(マスク生成)だけど、両項のMSBを反転してからpcmpgtdするより
psubd + psradのほうが速いかもしれない



763 名前:デフォルトの名無しさん mailto:sage [2012/03/14(水) 09:52:48.15 ]
>>762
どっちも2命令でXORの方が実行出来るポートが多い分有利そうに感じるのだが

764 名前:デフォルトの名無しさん mailto:sage [2012/03/14(水) 20:30:50.02 ]
pdangod

765 名前:デフォルトの名無しさん mailto:sage [2012/03/19(月) 10:59:48.11 ]
>>762
blendvps用のマスクならpsubdだけでよい
blendvpsは最上位ビットしか見ないから

766 名前:デフォルトの名無しさん mailto:sage [2012/03/21(水) 21:47:07.57 ]
話の流れぶった切るけど団子さんよ〜。
今の静的分岐予想って相変わらずifよりelseの方が速いの?
ifとelseのどっちが速いか正確に計測するにはどういうコード書いたらいい?

767 名前:デフォルトの名無しさん mailto:sage [2012/03/21(水) 23:28:17.45 ]
あれ?ifの方が速いんじゃなかったか

768 名前:デフォルトの名無しさん mailto:sage [2012/03/21(水) 23:53:20.16 ]
P6,P2,P3,P4はforwardならnot taken backwardならtakenがデフォルト
P4はPrefixでヒントを出せる
PM,Core2はランダム
ソースはAgner

769 名前:,, ・´ ∀ `・ ,,)っ-○○○ mailto:sage [2012/03/24(土) 09:22:43.82 ]
分岐予測履歴がない場合あるいは予測そのものがない場合、条件付ジャンプは前のアドレスに
飛ぶ場合(多くの場合ループ)は原則ジャンプ、後ろならスルーが多くのCPUの実装ですね。
大体のコンパイラってforやwhile文はこんな感じに展開するでしょ?
if (cond) { do { ... } while(cond); }

770 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 12:02:04.61 ]
>>769
モダンなCPUはどんな感じなのよ
>>768 はランダムだと言ってるけど
モダンなCPUでも静的予想だとifはスキップ
whileはループ確定なのけ。

771 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 19:11:37.76 ]
分岐履歴が無いのに前方への分岐を予測したら命令フェッチをやり直さなきゃならないじゃん
後方への分岐はループの場合が多いから特別扱いなんだと思う

772 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:14:58.62 ]
大概returnやthrowが行われるからifをすっ飛ばせば速いのは解る。
反復も反復する事を優先した方が早いのは解る。
それはいいとして、今のCPUは分岐ヒントとか投棄とかあって単純じゃないんだろ。
そこを知りたいんだがね。



773 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:25:07.37 ]
>今のCPUは分岐ヒントとか投棄とかあって単純じゃないんだろ。
パイプラインが深いだけでしょ

774 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:33:04.06 ]
わかってないのにわかったつもりになって
単語だけ並べているように見えるのは何故だろう

775 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:41:50.71 ]
そう思ってくれるのはいいが、間違いの指摘と
実際はどうなってんのか答えてくれ
批難だけの回答はいらん。

776 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:45:20.20 ]
>>773
分岐予測の話はパイプラインが深いこと前提で話してるわけで・・・

777 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:50:30.10 ]
>分岐予測
って、言い方してるだけなの?

778 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:52:06.49 ]
>>775
じゃあ間違いを指摘してやる。

>大概returnやthrowが行われるからifをすっ飛ばせば速いのは解る。
前方への条件分岐は、「分岐しない」と予測される、とオマエ以外の全員が言っている。
if (xx) return
で「すっ飛ばせば云々」なんて、理解していないまま「わかったつもりになってるだけ」の証拠。

>今のCPUは分岐ヒントとか投棄とかあって単純じゃないんだろ
ヒントはともかく、投機はまさに「投機実行するために分岐予測をする」のであって
「投機実行もあるから分岐予測が複雑になる」はナンセンス。
もちろん、エンプラ系/VLIW系では「分岐の有無の両経路を実行する」なんてのもある(らしい)が
一般的とは言いがたい。

779 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 21:59:34.64 ]
>>778
内容じゃなく国語的に誤解されてるな。

>前方への条件分岐は、「分岐しない」と予測される、とオマエ以外の全員が言っている。
if( xx ) throw xxx;
throwなんて実行するケース殆ど無いんだから基本if実行しないってのは同じ話。
矛盾してないでしょ。

まず分岐予測が複雑になってるって話はしてないよ。
投棄実行については投棄実行を考慮した上での静的予測方法があるでしょという話。

780 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:04:11.41 ]
>>779
だから、ifの内部は「実行すると予測される」んだよ、バーカ

781 名前:779 mailto:sage [2012/03/24(土) 22:05:34.03 ]
尤も、わかりやすいからifと書いたけど、
実際はコンパイラの最適化でif、elseは反転するから
この言い方は正しくは無いんだけどね。

782 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:06:41.25 ]
せめて正しい漢字使えよ。

一度なら単なる変換ミスとして納得できるけど
繰り返しているってことは、別の意味に捉えているとしか思えない。



783 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:09:32.88 ]
>>780
お前バカだろ
みんなアセンブリ前提で言ってんだよ

jze label   if() {
・・・処理・・・
labeli     }


784 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:12:25.76 ]
>>782
ん?尤も(もっとも)か?無い(ない)か?

785 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:20:41.79 ]
>投棄実行については投棄実行を考慮した上での静的予測方法があるでしょ

理解できる日本語で書いてくれないかな。

分岐予測というのは、投機的に(結果が判明する前に)実行する前提でのもの。
(無条件分岐や間接分岐もあるから、厳密には正しくないけど)
予想して(投機的に)実行するのでなければ、単に結果が判明するのを待って、それから実行すればよい。

つまり、投機実行するからこそ分岐予測が必要なのであって
投機実行しないのであれば、分岐予測など元々必要ない。
そのことをちゃんと理解していれば、
そもそも「投機実行を考慮しない分岐予測」などというものが存在しないから
>投棄実行を考慮した上での静的予測方法
が意味不明に感じられる気がするんだけどな。

>>783
わかってるよ、そんなこと。

786 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:22:22.48 ]
>>780 ifが優先されると思ってたのは>>767 とお前ぐらいだよ

787 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:25:19.71 ]
>>785
ごめん。もう今更何を言おうが>>780のせいで信用ないわ。

788 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:34:54.17 ]
>>782
ああ投棄実行ね投機の変換ミスそのままにしてたわ

789 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:48:33.55 ]
投棄実行については誤解してたわ。
2つの分岐を両方実行して実際実行対象にならなかった方の結果を破棄するものだと思ってた。

790 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 22:50:38.87 ]
>大概returnやthrowが行われるからifをすっ飛ばせば速いのは解る。

もう一度考えてみたけど、この意味が全然理解できない。
ぱっと見で、何故returnや、
増してthrowなどという言葉が出るのかわからない。
(GP等の例外の割り込みは全く別物)

で、次の行の
>反復も反復する事を優先した方が早いのは解る。
の意味は、「ループであることが推測されるから分岐すると予測する」だよね?
それとの対比で、「ifをすっとばせば」の意味が
「ifの内部は実行されないと予測」と捉えれば
「ifの部分での分岐は分岐すると予測すれば
if内部のreturnやthrowに制御が来ないので別の分岐の予測を避けられる」という意味にもとれる。
それならようやく意味が通じるような気がして、そういう意味だと思ったんだけど。
つまり、ifの部分(=前方分岐)を「分岐すると予測する」という意味だと。

でもそれ(前方へ分岐すると予測する)は実際のプロセッサの動作とは違うわけで
ならばどういう意味なのか、さっぱりわからなくなってしまってね。

791 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:00:43.72 ]
お前の文章が解らんわ

792 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:01:04.27 ]
一応。

突然returnやthrowが出てくるのが
if (xx) return
という意味じゃないか、というのも勝手に俺が頭の中で補って想像しただけで
実際には何の説明も無く(ifの多くがreturnやthrowというのにも同意しにくい)
唐突な「rerturnやthrow」「すっ飛ばす」を必死に理解しようとしたのがそもそもの間違いかもね。



793 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:01:51.31 ]
実行時の分岐予測って、どうなってるのかわかってないと、グダグダでしょ

794 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:04:39.09 ]
>>792
>>779で補足だしてるだろしつこいわ

795 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:09:08.21 ]
>>790 >>792 ウゼェ・・・


796 名前:デフォルトの名無しさん mailto:sage [2012/03/24(土) 23:18:44.32 ]
>>794
>>779だとしたら>>780だっての。
「前方分岐は分岐しないと予測する」のが実際のプロセッサの動作なわけ。
>>779の「throwなんか滅多に起こらないから実行しない(と予測する)」は
「前方分岐は分岐すると予測する」ことになるから実際の動作と矛盾するという話。
それを、「わかってないくせに」の根拠の一つにしたんだよ。

実際、「分岐予測とはどういうものか」も「なぜ分岐予測するのか」もわかってなかったわけでしょ(>>789)。

797 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 01:09:12.01 ]
口汚い言葉で罵倒せずには居られない奴って下品・・・。
団子さんの紳士っぷりを少しは見習ったらどうだろうか。

798 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 01:16:07.87 ]
もう>>780はいいから団子さんこないかな

799 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 01:24:14.75 ]
え?指摘するの780だけ?
露骨だなぁ。恥ずかしくないんだろうか。

800 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 02:30:29.23 ]
お前がなwww

801 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 03:19:03.04 ]
頭が悪すぎて理解できなかったらしいから仕方ないな。

802 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 14:12:21.08 ]
>>796
投機実行という言葉については誤解してました。
分岐予測については、分岐ミスでパイプラインに読み込んだ
命令を破棄が発生するという認識です。

そもそも、それが気にならないのであれば分岐予測なんて
気にする必要はないでしょう。



803 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 16:12:43.94 ]
インテルの最適化マニュアルだと
>インテルPentiumM プロセッサー、インテルCoreSolo プロセッサー、インテルCoreDuoプロセッサーは、
>ジャンプの向きに従った条件分岐を静的には予測しない。これらのプロセッサーでは、
>すべての条件分岐は、最初に発生したときでも動的に予測される。
と書いてあって、wikiで調べたらPenM以降は広域分岐予測を取り入れた関係で静的予測はしなくなったみたいだね
ttp://ja.wikipedia.org/wiki/%E5%88%86%E5%B2%90%E4%BA%88%E6%B8%AC

>>768
>PM,Core2はランダム
というよりも、「前に実行した別の分岐命令の結果も影響する」とした方が適切みたいだ

分岐予測に関して
ttp://news.mynavi.jp/column/architecture/index.html
の第167回からの解説が参考になるよ


804 名前:デフォルトの名無しさん mailto:sage [2012/03/25(日) 18:09:59.76 ]
>>803
なるほど。いい話が聞けました。ありがとうございます。

805 名前:デフォルトの名無しさん mailto:sage [2012/03/28(水) 00:06:00.96 ]
>>803
>と書いてあって、wikiで調べたらPenM以降は広域分岐予測を取り入れた関係で静的予測はしなくなったみたいだね
P4もグローバル履歴を使ってるよ

おそらくだけど ある分岐命令を最初に実行したかどうかはBTBのエントリが割り当てられているかで判断するので
分岐先予測より分岐予測のヒット率が十分に高い場合は動的分岐予測が当たる条件で誤って静的予測してしまう確率が高いから
1回目の分岐予測を諦めても静的予測をやめたほうがヒット率が上がるということなんじゃないだろうか

806 名前:デフォルトの名無しさん mailto:sage [2012/03/28(水) 00:11:22.64 ]
×分岐先予測より分岐予測のヒット率が十分に高い場合
○BTBのヒット率より分岐予測のヒット率が高い場合






[ 新着レスの取得/表示 (agate) ] / [ 携帯版 ]

前100 次100 最新50 [ このスレをブックマーク! 携帯に送る ] 2chのread.cgiへ
[+板 最近立ったスレ&熱いスレ一覧 : +板 最近立ったスレ/記者別一覧]( ´∀`)<188KB

read.cgi ver5.27 [feat.BBS2 +1.6] / e.0.2 (02/09/03) / eucaly.net products.
担当:undef