- 1 名前:デフォルトの名無しさん mailto:sage [2007/04/29(日) 09:54:14 ]
- コンパイラ性能、コンパイルオプション、コードの最適化などについて語りましょう。
主に速度面の最適化を中心としますが、サイズなどの最適化もどうぞ。 なお、OS、CPU、コンパイラなどは限定しません 前スレ C、C++の最適化について語るスレ pc11.2ch.net/test/read.cgi/tech/1084676298/
- 533 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 22:00:28 ]
- ある C++ のメソッドを アセンブラに書き換えたら、かえって実行速度が遅くなった orz
- 534 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 22:12:21 ]
- あるある。
コンパイラってマジ賢いわ。
- 535 名前:533 mailto:sage [2008/03/12(水) 22:25:43 ]
- それがさー 多倍長整数の1ビットシフトと論理積処理なんだぜ
r = (r << 1) & mask; // r, mask は多倍長整数 こんな単純な処理はキャリービットを使ったシフト命令が使えるアセンブラの方が絶対速いはずなのだが アセンブラにすると、グローバルな最適化がうまくできないみたいで、C++ よりも遅くなったみたい
- 536 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 22:28:49 ]
- そう言うときはどういう処理吐いてるか見た方がいいよ。
- 537 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 22:30:44 ]
- >>535
差し支えなければC++とasm双方晒してくれ。
- 538 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 22:31:22 ]
- 局所的な最適化は必ずしも大局的な最適化とはならない事のいい例だね。
例えば最近のコンパイラなんかは、一回のコンパイル時間が長くなっても エラーメッセージなどを丁寧に出力するから、結果的にコードを修正する時間が短くなって コンパイル回数も減り、開発時間が短くなる事に寄与している。 コンパイラ賢い。
- 539 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 23:01:49 ]
- >>535
パイプラインが詰まるようなコード書いたんじゃねーの。
- 540 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 23:05:20 ]
- キャリーっていう1つしかない資源を使う限り、
詰まらざるを得ないんじゃないかな。
- 541 名前:デフォルトの名無しさん mailto:sage [2008/03/12(水) 23:19:41 ]
- 多少コードが増えてもCPIが上がれば逆転するから、安易なインラインアセンブラの使用は割に合わない。
- 542 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 12:36:23 ]
- asmのおかげで回りの最適化が効かなくなってんじゃないか?処理時間の短い関数をasmにしても逆効果だよ。
ループを含めるとか、ある程度処理時間がかかる部分をasmに直そうよ。
- 543 名前:536 mailto:sage [2008/03/13(木) 19:09:16 ]
- もちろんコンパイラが吐き出してるソースチェックしたよ
そしたら グローバルに最適化されてるってことがわかったんだよ
- 544 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:10:14 ]
- >>537
うーん、そのままだとちょっと差し支えがあるので、 晒せるように書き直せるかどうか試してみるよ
- 545 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:20:37 ]
- >グローバルに最適化
の意味が解らん
- 546 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:42:37 ]
- 以下のようなクラスがあって
class CShiftAnd { uint m_nReg; uint *m_pR; uint *m_pCV; uint m_exitIndex; uint m_exitMask; public: CShiftAnd(int); ~CShiftAnd(); bool setEntryState(); void transition(uchar); void transition_asm(uchar); };
- 547 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:42:59 ]
- bool CShiftAnd::setEntryState()
{ *m_pR |= 1; return (m_pR[m_exitIndex] & m_exitMask) != 0; } void CShiftAnd::transition(uchar ch) { uint *ptr = m_pR; uint *pCV = m_pCV + (ch * m_nReg); uint carry = 0; for(uint i = 0; i < m_nReg; ++i, ++ptr) { uint nextCarry = *ptr >> 31; *ptr = (*ptr << 1) + carry; *ptr &= *pCV++; carry = nextCarry; } }
- 548 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:43:53 ]
- void CShiftAnd::transition_asm(uchar ch)
{ uint *pR = m_pR; uint *pCV = m_pCV + (ch * m_nReg); uint nReg = m_nReg; __asm { mov edi, pR ;; edi = m_pR mov esi, pCV mov ecx, nReg xor eax, eax ;; clear carry L01: mov eax, [edi] adc eax, [edi] and eax, [esi] mov [edi], eax lea edi, [edi+4] lea esi, [esi+4] loop L01 } }
- 549 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:45:47 ]
- 以下のコードでタイムを計測した
buf のサイズは1000なので、10億回ループする { StopWatch<> sw; CShiftAnd sa(31); for(int i = 0; i < 10000 * 10; ++i) { int count = 0; for(cchar *ptr = buf; ptr < buf + sizeof(buf); ) { if( sa.setEntryState() ) count += 1; sa.transition(*ptr++); } } }
- 550 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 19:47:27 ]
- おいらの環境でタイムを計測すると
1.125秒 sa.transition(*ptr++); を sa.transition_asm(*ptr++); に変えてタイムを計測すると 1.469秒 だった
- 551 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:05:19 ]
- 中身全然理解してないけど
なんでedxを使わないでレジスタ変数に使われる(push/popが必要な)esiやediを使ってるの、とか あなたの読んだ最適化に関する文書に、LOOPを使うことについて何か触れられてなかったのか、とか
- 552 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:20:27 ]
- >>551
じゃ、アセンブラでどう書いたら高速になるのかコードを晒してくおくれ
- 553 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:24:49 ]
- 何が「じゃ」なんだろ。まったく話が繋がってない。
- 554 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:30:54 ]
- >>552
最適化技法の専門書でも読め
- 555 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:38:59 ]
- C++のソースレベルで見ても
ロード/ストアの形にするのも基本だし カウンタ(i)を用意して非定数のlimitと比較するくらいなら、first/last形にするのが常識だし (まあこれは0との比較に変えてるみたいだからいいか) といっても、その程度は最適化コンパイラなら当たり前にやっていることだけど
- 556 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 20:42:18 ]
- で、結局、「グローバルに最適化」とは何なのだろう。
- 557 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 21:16:13 ]
- >>538の「大局的な最適化」と同じ意味だろう。
別に何かの規格で定められた専門的な用語ではないはずだ。 いや、わかっててネチっこく絡んでるだけなら、野暮な説明だけど。
- 558 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 21:29:52 ]
- おまいらもっと速いアセンブラのコード晒してやれよ
- 559 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 21:33:39 ]
- >>557
いや、だから「どこを見てコンパイラが大域的な最適化をしていると判断したか」という話よ。 単に「自分の書いた(付け焼刃の)アセンブラより速かったから 大域的な最適化をしているに違いない」と言ってるとしか見えないわけさ。
- 560 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 21:51:33 ]
- >>559
543 名前:536[sage] 投稿日:2008/03/13(木) 19:09:16 もちろんコンパイラが吐き出してるソースチェックしたよ そしたら グローバルに最適化されてるってことがわかったんだよ
- 561 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/13(木) 21:55:30 ]
- VC++は、インラーインアッセンブルルルルァ使った関数はインライン展開とかできません。
- 562 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 21:58:27 ]
- 余計意味わかりませんけど。
例えば、そのグローバルな最適化によって、 >>547はどのようなアセンブラコードになるのですかね?
- 563 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 22:00:06 ]
- ☆ チン マチクタビレタ〜
マチクタビレタ〜 ☆ チン 〃 ∧_∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ヽ ___\(\・∀・) < 速いアセンブラソースまだ〜? \_/⊂ ⊂_ ) \_____________ / ̄ ̄ ̄ ̄ ̄ ̄ /| | ̄ ̄ ̄ ̄ ̄ ̄ ̄| | | 愛媛みかん |/
- 564 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 22:34:20 ]
- 団子さんのレスが期待されるところだ
- 565 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 22:43:23 ]
- いやもうレスしただろ
- 566 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/13(木) 22:57:30 ]
- SSEの使えないコードは汗んブラないのが俺のモナー
よく読んでないけど使えそうだけどな
- 567 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:16:51 ]
- >>559
> いや、だから「どこを見てコンパイラが大域的な最適化をしていると判断したか」という話よ。 このタイミングで急に新しい話題始めるんですかー。
- 568 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:17:12 ]
- loop は遅いから使わないってのは基本だと思うんだがなあ。
- 569 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/13(木) 23:27:44 ]
- コンパイラより自分でアセンブったコードの方が速いと根拠もなく信じてる人もたまにいるので。
- 570 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:29:10 ]
- そんなん信じてる馬鹿ここにはまずこないんじゃないの
- 571 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:31:02 ]
- x86・RISCやキャッシュてんこ盛りのプロセッサだと今時のコンパイラを超えるのは至難だろうな。
組み込み系の貧弱な石ならアセンブラの方が速い事は多々あるけど。
- 572 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:31:52 ]
- コンストラクタ無し/デストラクタ無し/初期化されず説明の無いメンバ変数。
速いコードは書けないが、動かないコード晒されると更にやる気を削がれるな。 >>556 SSE使えるならむしろCって考え方も。 >>568 最近はmicro op fusionとかやってるから高級な命令の方がAMDみたく都合よくなるんじゃない?
- 573 名前:デフォルトの名無しさん mailto:sage [2008/03/13(木) 23:34:07 ]
- 安価ミスった。556じゃなくて>>566
- 574 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/13(木) 23:36:35 ]
- VCなんかだとthisポインタはecx渡しになるからそこんとこ考えてコード組む必要がある。
- 575 名前:デフォルトの名無しさん mailto:sage [2008/03/14(金) 00:20:39 ]
- >>548
ところで、このコードは正しい結果が出るか確認したか?
- 576 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/14(金) 00:23:47 ]
- んでもって>>548はecx使っちゃってるね
- 577 名前:デフォルトの名無しさん mailto:sage [2008/03/14(金) 12:16:54 ]
- >>548
86のアセンブラなんて10年以上やってないんで自信ないんだが、途中でキャリーフラグ消えてないか? キャリー使わずにCで書いても同じくらいの速さのコードは出そうだが。
- 578 名前:デフォルトの名無しさん mailto:sage [2008/03/14(金) 13:01:13 ]
- >>577
mov, lea, loop はキャリーに影響しない add edi, 4 でなく lea edi, [edi + 4] とするのはそのためでもある
- 579 名前:デフォルトの名無しさん mailto:sage [2008/03/14(金) 21:39:30 ]
- >>578
andも?
- 580 名前:デフォルトの名無しさん mailto:sage [2008/03/14(金) 22:07:37 ]
- >>579
少しは自分で調べろ
- 581 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/15(土) 00:05:39 ]
- andは書き換えるだろ。
MMX/SSEもフラグレジスタを書き換えない。
- 582 名前:デフォルトの名無しさん mailto:sage [2008/03/17(月) 10:24:25 ]
- Cとインラインアセンブラのソースを睨めっこしても意味ないだろ
逆汗しないと
- 583 名前:デフォルトの名無しさん mailto:sage [2008/03/17(月) 10:36:22 ]
- はぁ?
- 584 名前:デフォルトの名無しさん mailto:sage [2008/03/17(月) 10:57:39 ]
- はぁ。
- 585 名前:デフォルトの名無しさん mailto:sage [2008/03/17(月) 12:13:54 ]
- ハァ〜ン
- 586 名前:デフォルトの名無しさん [2008/03/18(火) 20:20:53 ]
- 例A)
gethoge()->fuga(); gethoge()->piyo(); 例B) hoge *p = gethoge(); p->fuga(); p->piyo(); gethogeはprivate変数へのアクセサと仮定して、 この場合例AとBでどっちの方が早いのだろう? fugaやpiyoがもっとたくさんあるのなら後者だろうけど 2回だけだとポインタこさえるコストも考えるとごっちゃになってきた。
- 587 名前:デフォルトの名無しさん mailto:sage [2008/03/18(火) 21:40:21 ]
- ちゃんとインライン化されれば同じようなもんだろ。
- 588 名前:デフォルトの名無しさん mailto:sage [2008/03/19(水) 10:47:54 ]
- >>586
処理時間で A >= B って感じ。 「ポインタこさえるコスト」とか言うが、 A でもコンパイラが ポインタを作る。しかも繰り返し。
- 589 名前:デフォルトの名無しさん mailto:sage [2008/03/19(水) 12:29:58 ]
- fugaの中でhogeが書き換わる可能性を考慮すると、AとBでは結果が異なる可能性がありそうな気も
- 590 名前:デフォルトの名無しさん mailto:sage [2008/03/21(金) 13:27:23 ]
- それをいうならgethogeじゃない? fuga一回しか呼んでないじゃん
- 591 名前:デフォルトの名無しさん mailto:sage [2008/03/21(金) 21:02:41 ]
- fugaとpiyoを呼んでprivate変数の状態を変えるとか考えないのか?
- 592 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 09:42:59 ]
- vtuneって各関数でのメモリアクセス数って調べられますか?
- 593 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 12:24:39 ]
- 遅延量や、キャッシュミスもわかる。
- 594 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 14:16:56 ]
- memoryのpageinput/outputを監視すれば
各関数のメモリアクセスは調べられそうですね ありがとうございます。
- 595 名前:デフォルトの名無しさん [2008/03/26(水) 14:44:33 ]
- >>594
writeとreadはいらないの?
- 596 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 15:25:04 ]
- >>595
メモリアクセスはin/outだけじゃ・・・
- 597 名前:デフォルトの名無しさん [2008/03/26(水) 16:07:31 ]
- vtunesの使いかた分かんね。
どうやったらプログラム実行終了時の 各関数のそれぞれにおいてのメモリアクセス数が出るんだ
- 598 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 18:58:16 ]
- >>597
命令ごとのメモリや演算器、キャッシュ、バスのタイミングが見える。プロファイラなんかとは次元が違う。
- 599 名前:デフォルトの名無しさん mailto:sage [2008/03/26(水) 21:43:23 ]
- >>598
それぞれのメモリアクセスはどこみればいいのか分からん 全体の1秒あたりのメモリアクセスは出てるけど
- 600 名前:デフォルトの名無しさん [2008/03/29(土) 09:07:38 ]
- vectorって配列に比べて最適化されにくい?
- 601 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/29(土) 09:13:42 ]
- そうでもないよ
- 602 名前:デフォルトの名無しさん mailto:sage [2008/03/29(土) 09:40:39 ]
- ダンゴさんは博識にもほどがあるな
- 603 名前:デフォルトの名無しさん mailto:sage [2008/03/29(土) 09:56:57 ]
- スタックに置く場合以外は同じだろうね。
- 604 名前:デフォルトの名無しさん mailto:sage [2008/03/29(土) 12:12:58 ]
- 602 名前:あぼ〜ん[あぼ〜ん] 投稿日:あぼ〜ん
- 605 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/03/29(土) 12:29:13 ]
- 上に同じ
- 606 名前:デフォルトの名無しさん mailto:sage [2008/03/29(土) 23:47:37 ]
- 「TASさん」みたいなノリですね、わかります。
- 607 名前:デフォルトの名無しさん mailto:sage [2008/03/30(日) 00:55:13 ]
- ダンゴさんの書き込みでスレが再加熱したな
- 608 名前:デフォルトの名無しさん mailto:sage [2008/03/30(日) 00:59:22 ]
- 607 名前:あぼ〜ん[あぼ〜ん] 投稿日:あぼ〜ん
- 609 名前:デフォルトの名無しさん [2008/03/30(日) 02:23:09 ]
- 608 名前:あぼ〜ん[あぼ〜ん] 投稿日:あぼ〜ん
- 610 名前:デフォルトの名無しさん mailto:sage [2008/03/30(日) 10:57:30 ]
- あぼ〜ん推奨ワード:ダンゴ、だんご、団子
- 611 名前:デフォルトの名無しさん mailto:sage [2008/03/30(日) 11:22:37 ]
- 610 名前:あぼ〜ん[あぼ〜ん] 投稿日:あぼ〜ん
- 612 名前:デフォルトの名無しさん mailto:sage [2008/03/30(日) 17:47:20 ]
- >>610-611
w
- 613 名前:デフォルトの名無しさん mailto:sage [2008/03/31(月) 02:51:59 ]
- w ってどういう意味?
- 614 名前:デフォルトの名無しさん mailto:sage [2008/03/31(月) 03:08:41 ]
- 藁w
- 615 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 00:18:25 ]
- >>614 には失望した
- 616 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 01:05:43 ]
- なら俺は干草
- 617 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 10:00:38 ]
- >>600
コンパイラによるがされにくい。 PGIでは、vectorのまま[]でアクセスしたループはベクトル化してくれないが、 一旦ポインタに変換してループを書くとベクトル化する。
- 618 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 10:52:06 ]
- vector使うなら、operator[]を使わずにiteratorを使うだろ。常考
- 619 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 15:40:33 ]
- iteratorなんかつかったら余計に最適化されねーっての。
- 620 名前:デフォルトの名無しさん mailto:sage [2008/04/01(火) 16:37:25 ]
- されますが何か。
- 621 名前:デフォルトの名無しさん mailto:sage [2008/04/02(水) 15:05:29 ]
- その手があったか。
vectorに限って言えばiteratorはまず間違いなくポインタだろ。 ということは最適化される。
- 622 名前:619 mailto:sage [2008/04/02(水) 16:20:53 ]
- すんません。
vector<double>::iterator p = v.begin(); を使って、 p[i] でアクセスしたらポインタと同等の最適化されました。 ただ、for文の終了条件を p != v.end() なんてことしたら ループの回数が不明ということで最適化除外されました。
- 623 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/04/02(水) 17:00:57 ]
- std::vector<F32vec4>
から派生の方向で アクセッサ?ほぼ再実装だね
- 624 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2008/04/02(水) 17:02:21 ]
- >>622
コンパイラは?
- 625 名前:デフォルトの名無しさん mailto:sage [2008/04/02(水) 23:37:03 ]
- ダンゴさんはVCの最適化については一言言いたいところがあるようだな
- 626 名前:デフォルトの名無しさん mailto:sage [2008/04/02(水) 23:48:28 ]
- >>624
PGI
- 627 名前:デフォルトの名無しさん [2008/04/03(木) 00:23:08 ]
- 623 名前:あぼ〜ん[あぼ〜ん] 投稿日:あぼ〜ん
- 628 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 13:17:37 ]
- >p != v.end()
毎回インスタンス変数見るのか。 for(int i=0,sz=v.size(); i<sz; i++){...} for(iterator i=0,end=v.end(); i!=end; i++){...} のどちらかだろ常考。
- 629 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 14:51:29 ]
- 本来その程度の事は自動でやってくれるべきだけどね。
高級アセンブラだから細かいところに気を使うんだよな。
- 630 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 15:13:25 ]
- それを自動でやったらvolatileを勝手に外すくらいの暴挙じゃね?
正当にやれるのは、v自体がローカル変数で、 ポインタを取られてないことを解析出来る場合だけど、 その前提を維持するより一時ローカル変数に移した方が簡単だと思う。
- 631 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 16:33:26 ]
- ああそうか。あー!面倒くさい!
もうローカルでポインタを取得してないメンバ変数やグローバル変数が 外から変更される可能性がある場合は全部volatile付けるって事でいいよw なんてやってるとvolatileだらけでどっちが面倒くさいんだか分からなくなってくるな。
- 632 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 18:15:58 ]
- パソコンだとマルチスレッドなんてあるから、
volatileが付いていてもいなくても 付いているのと同じように扱われている気がする(ローカルな自動変数以外)。
- 633 名前:デフォルトの名無しさん mailto:sage [2008/04/03(木) 19:18:06 ]
- volatileは厳密にメモリのアクセス回数を決めるための物だから
同じってことは無いだろうけどね。
|

|