[表示 : 全て 最新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などによる高速化の手法
について語りましょう。

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より分岐のほうが速いはず)






[ 続きを読む ] / [ 携帯版 ]

前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