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