- 1 名前:デフォルトの名無しさん mailto:sage [2005/10/27(木) 02:55:36 ]
- C++やインラインアセンブラ、SSEなどによる高速化の手法
について語りましょう。
- 610 名前:デフォルトの名無しさん mailto:sage [2011/06/15(水) 01:38:06.85 ]
- キャッシュが考慮されてないよね
- 611 名前:デフォルトの名無しさん mailto:sage [2011/06/15(水) 01:49:45.83 ]
- > 間違いですよね?
その通り。 >>608 総和とか本当にメモリがボトルネックだとスカラでやっても大して変わらない。 >>609 そう、机上は本当に大ざっぱな見積もりだけで基本的には実測が重要。 でもVTuneなんかは他にも項目が多過ぎて目星付けるのも勘がいるんだよ。
- 612 名前:デフォルトの名無しさん mailto:sage [2011/06/15(水) 16:31:35.18 ]
- SSE使わんと絶対にプリフェッチされない、とかだったら正しかった。
- 613 名前:デフォルトの名無しさん mailto:sage [2011/06/15(水) 21:26:27.67 ]
- >>610 畳み込みとの違いのヒントを示し忘れてた。
同じアドレスを複数回読むなら、最初の1回を見積もりに入れておけばいい。 勿論キャッシュに入らないサイズだと全てカウントする必要がある。
- 614 名前: ◆0uxK91AxII mailto:sage [2011/06/16(木) 15:08:44.21 ]
- メモリ周りがボトルネックなら、prefetch*とmovnt*。
とりあえず、CPUによっては32[bit]のmovntiは遅いから使わない方向で。 実行環境が単一でない場合、大雑把な見積もりで十分だと思ってみる。
- 615 名前:デフォルトの名無しさん mailto:sage [2011/07/02(土) 13:07:18.11 ]
- VCの__declspec(align(16))や#pragma pack(push, 16)って
一時オブジェクトには効かないんでしょーか? std::map、std::pair周りをソースひっぱってきて、__m128を含んだクラスを 受け取れるようにしたんですが、 aligned_stl::pair<int, hoge> pairArg = aligned_stl::make_pair(1, Hoge); mapFuga.insert(pairArg); とやるといけるけど mapFuga.insert(aligned_stl::make_pair(1, Hoge)); とすると、一時オブジェクトがアラインされてなくてこけます・・・・ 何か抜け道ないですかね(´・ω:;.:...
- 616 名前:デフォルトの名無しさん mailto:sage [2011/07/02(土) 13:20:21.30 ]
- 間違えたorz
”make_pairの返す一時オブジェクトが”アウトですた。 make_pair(1, Hoge); ←×(落ちる。) aligned_stl::pairArg(1, Hoge); ←○(落ちない。) なのでコンストラクタで直接渡せばいけるけども。 Hogeにもpairにもアライン指定つけてるんだけどなぁ・・・
- 617 名前:デフォルトの名無しさん mailto:sage [2011/07/02(土) 13:22:04.01 ]
- また間違えた・・・・連投すみませんorz
誤:aligned_stl::pairArg(1, Hoge); ←○(落ちない。) 正:aligned_stl::pair<int, hoge>(1, Hoge); ←○(落ちない。)
- 618 名前:デフォルトの名無しさん mailto:sage [2011/07/02(土) 22:44:49.03 ]
- mapの方がアライメントされてないんじゃない?
- 619 名前:デフォルトの名無しさん mailto:sage [2011/07/02(土) 23:38:54.68 ]
- std::pair<int, hoge>からaligned_stl::pair<int, hoge>へのコードがバグってるんじゃないの
- 620 名前:618 mailto:sage [2011/07/03(日) 00:21:26.44 ]
- 適当な事書いたと思ったけど、std::mapにカスタムアロケータでいけるっぽい
ttp://ideone.com/sOWl6
- 621 名前:デフォルトの名無しさん mailto:sage [2011/07/03(日) 02:45:36.94 ]
- >>618
mapの方は、__declspec(align(16))みたいなことはしてませんが カスタムアロケータを渡しており、カスタムのpair(aligned_stl::pair)を使うように指定してます。 >>619 わかりづらくてすみませんorz std::pairは一切使っておらず、aligned_stl::pairのみです。 make_pairもaligned_stl::pairを返します。 >>620 ありがとうございます、Win7 64bitのVC2008Expressで動かしてみましたが カスタムアロケータのc.insertで、Hoge()の引数なしのコンストラクタで落ちます(x_ = static_x) Hoge hoge; c.insert( ::std::make_pair<int,Hoge>(i, hoge) ); とやると、make_pairのところのコピーコンストラクタで落ちます( x_ = src.x_)。 なので、前回書いたのと同様に Hoge hoge; std::pair<int, Hoge> pairArg(i, hoge); とやってからpairArgを渡すと落ちませんでした(c.insertのみ。d.insertは落ちる)。 どうもpairに関してはアラインメント指定しなくても、中のメンバが アラインメント指定されていれば問題ないようですね(アロケータだけでよい?)。 もうちょっと試してまた報告します。 ただ、2008だとアラインメント指定が一時オブジェクトに対して効かないと考えたほうが いいのかもしれませんね(´・ω:;.:... (インライン展開された場合は除く) ありがとうございました。
- 622 名前:621 mailto:sage [2011/07/03(日) 03:25:25.25 ]
- あと、x64をターゲットにすれば落ちませんでした(デフォルトのアラインメントが16バイトだから?)
ついでに質問なのですが、>>620のchar unused1__とunused2__はどういう意味でしょうか?
- 623 名前:デフォルトの名無しさん mailto:sage [2011/07/03(日) 03:47:36.78 ]
- それって構造体のメンバのアライメント指定であって、アドレスのアライメント指定する機能って基本的になくね。
x64だと関数の始まりのスタックは16バイトアライメントになるようになってるから、問題発生しにくいとか。 というか、落ちる落ちない以前にデバッガで逆アセ見れば、どういうコードが生成されているかすぐわかると思うんだが。
- 624 名前:デフォルトの名無しさん mailto:sage [2011/07/03(日) 04:52:17.82 ]
- >構造体のメンバのアライメント指定であって
あああ、なるほど・・・x64なら安全、と考えるのは危険ですね。 >逆アセ見れば 見てます、きっちりmovaps使ってますw で、ウォッチ窓で見ると一時オブジェクト側のアドレス下位1バイトが0でないので 明らかにアラインされてないのが問題です。 __m128を使うだけなら、構造体の代入演算子やコピーコンストラクタで _mm_loadu_psとか使えばいいんでしょうけど。 誤解されるような書き方だったかもしれません、決して手詰まりというわけではないです。 どうにかしてアラインメント保ったままmapに突っ込めないかなー、というだけでした。
- 625 名前:618 mailto:sage [2011/07/03(日) 11:13:12.43 ]
- ダメ、だったか・・・ (Initial D 星野好造風に)
2010だからこっちでは本来の動作確認はできないけど、コレならどうだろう ttp://ideone.com/h4QFh
- 626 名前:621 mailto:sage [2011/07/03(日) 15:51:09.00 ]
- >星野好造風に
渋すぎるwww ありがとうございます、試して無事動きました(#if 1でも0でも) 予測しておられた?通り、char unused1__が含まれていようと問題ないんですね。 構造体の型自体は(__m128のような16byte境界を要求するものが含まれていれば) 先頭アドレスが16byte境界でさえあればいいような配置になっているけど、 2008は関数の返す一時オブジェクトのアドレス調整が抜けている、ということかな・・・ 大変参考になりました、ありがとうございました。
- 627 名前:デフォルトの名無しさん mailto:sage [2011/07/03(日) 22:56:56.22 ]
- int i = 10;
int * p = &i;//int型ポインタpにiのアドレスを代入する 簡単。 char str1[] = "abcde"; char * str2 = "abcde"; 上と下は同じでどっちを使ってもいい。
- 628 名前:デフォルトの名無しさん mailto:sage [2011/07/03(日) 22:59:55.40 ]
- sizeof(str1) != sizeof(str2)
- 629 名前: ◆0uxK91AxII mailto:sage [2011/07/04(月) 00:40:54.13 ]
- str1++;
- 630 名前:sage [2011/07/05(火) 07:42:33.24 ]
- sizeof とか return とかにかならずカッコをつける人がいるけど何で?
- 631 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 08:17:06.42 ]
- sizeofとdefinedは関数として意味が通ってるから括弧付けちゃうな。
(a || b) && (c || d) も括弧いらないけど、あった方が読みやすいのと似てる。 returnに括弧付ける人の気持ちは聞いた事が無いから分からない。
- 632 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 08:18:59.63 ]
- 間違えた(a && b) || (c && d)だ。
- 633 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 08:43:27.32 ]
- >>630
sizeofの中身によって括弧つけたりはずしたりしてるのかい? おれはそんなとこ気を使っても意味ないと思うので常につけてる。 sizeofの括弧省略してるコードってほとんど見たこと無いしな。
- 634 名前: ◆0uxK91AxII mailto:sage [2011/07/05(火) 14:20:59.67 ]
- >>630
struct s{int i;}; sizeof struct s; :b
- 635 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 19:23:54.89 ]
- 20年以上C書いてるけど、sizeof のカッコが省略可能なんて知らなかった…実際そんな記述を見たことがなかった。
return にはカッコつけない。
- 636 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 19:33:01.76 ]
- return (0); とかは見たことあるけど、sizeof int は見たことないからなぁ。
- 637 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 19:36:15.27 ]
- それは違反です
- 638 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 22:56:13.54 ]
- 余分なカッコが多すぎるコードってみにくくて嫌いだ。
if (a == 0 && b == 0 || c == 0 && d == 0) if ((((a == 0) && (b == 0)) || ((c == 0) && (d == 0)))) この二つだと上の方がはるかに見やすいと個人的には思うが、 見やすさを優先してカッコをつけるとか言って下のように書く人がいる。
- 639 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 23:13:08.81 ]
- LISPに慣れているせいか、かっこをつけておくと
式の構造が立体的に(ネストが深いほど浮き上がって)見えるんだ
- 640 名前:デフォルトの名無しさん mailto:sage [2011/07/05(火) 23:16:36.97 ]
- 確かに人間が見ると見やすいかも知らないが、
人間以外(コードアナライザの類とか)には 見やすくないと判断されるんで仕方がなくつけてる。
- 641 名前:デフォルトの名無しさん mailto:sage [2011/07/06(水) 00:43:52.44 ]
- >>638
if ( ((a == 0) and (b == 0)) or ((c == 0) and (d == 0))) って書く。論理演算はキーワード使う方がビット演算との取り違えも防げる。
- 642 名前:デフォルトの名無しさん mailto:sage [2011/07/06(水) 00:54:25.86 ]
- AndAlsoですね、わかります
- 643 名前:デフォルトの名無しさん mailto:sage [2011/08/01(月) 22:47:25.26 ]
- >>638
何処からが"余分"なのかを巡って紛糾する事も多し。
- 644 名前: ◆0uxK91AxII mailto:sage [2011/08/02(火) 00:52:38.09 ]
- #define EQUAL(a, b) (a==b)
#define OR(a, b) (a||b) #define AND(a, b) (a&&b) if (OR(AND(EQUAL(a, 0), EQUAL(b, 0)), AND(EQUAL(c, 0), EQUAL(d, 0)))) 見づらいって言うか、吐き気がするほど読みづらい。
- 645 名前:デフォルトの名無しさん mailto:sage [2011/08/02(火) 08:50:56.65 ]
- こんな手法でちまちま高速化したところで、もっと簡単なGPGPUの並列処理に
圧倒されるだけ。
- 646 名前:デフォルトの名無しさん mailto:sage [2011/08/02(火) 19:46:47.70 ]
- GPGPUが簡単? OpenCLの厄介さを身を以て知って濃い。
- 647 名前:デフォルトの名無しさん mailto:sage [2011/08/02(火) 22:19:04.98 ]
- if ((!a && !b) || (!c && !d))
- 648 名前:デフォルトの名無しさん mailto:sage [2011/08/02(火) 22:20:48.41 ]
- 括弧が
- 649 名前:デフォルトの名無しさん [2011/10/10(月) 19:26:30.72 ]
- 指定桁数で四捨五入する以下の関数の実行速度を上げたいの。
(valueは0〜9999、digitsは0〜5が保証される) SSE使って高速化頼む。 double NormalizeDouble(double value, 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 }; return (int)(value * t0[digits] + 0.5) * t1[digits]; }
- 650 名前:デフォルトの名無しさん mailto:sage [2011/10/10(月) 19:27:11.99 ]
- ベクトル化は不要よ。
- 651 名前:デフォルトの名無しさん mailto:sage [2011/10/10(月) 19:39:28.17 ]
- あら、なんかデジャブ
- 652 名前:デフォルトの名無しさん mailto:sage [2011/10/10(月) 19:49:57.12 ]
- >>649
最適化スレで終了宣言してからにしろよ
- 653 名前:デフォルトの名無しさん mailto:sage [2011/10/10(月) 19:50:50.26 ]
- でもベクトル化で少しは早くなるわよ
- 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向けのゲームとか組まされてるわけ?
|

|