C、C++の最適化について語るスレ 2
at TECH
1:デフォルトの名無しさん
07/04/29 09:54:14
コンパイラ性能、コンパイルオプション、コードの最適化などについて語りましょう。
主に速度面の最適化を中心としますが、サイズなどの最適化もどうぞ。
なお、OS、CPU、コンパイラなどは限定しません
前スレ
C、C++の最適化について語るスレ
スレリンク(tech板)
2:デフォルトの名無しさん
07/04/29 12:32:25
2げtt
3:デフォルトの名無しさん
07/04/29 15:13:32
ポインタ使ったほうが速いの?
4:デフォルトの名無しさん
07/04/29 15:18:14
コンテナにオブジェクト詰めるときは
newしてそのポインタを詰めるとめがっさ軽くなる
5:デフォルトの名無しさん
07/04/29 15:36:28
>>3-4
オブジェクトのコピーがボトルネックになってる場合に限るけどな。
6:デフォルトの名無しさん
07/05/01 17:49:32
GPOを行う場合、1000回計算を行うループがあったとして、10回程度ループを回して計測して、最適化することはできないでしょうか?
一旦プログラムのすべてを実行しなければならないとしたら、毎回実行条件の違う
科学計算などではどのように最適化すればよいのでしょうか?
7:デフォルトの名無しさん
07/05/01 22:49:32
それは分岐予測というカタチでハードウェアが実行している。
コンパイラはそれが機能しやすいようにする。
8:デフォルトの名無しさん
07/05/02 02:20:57
ダンゴさんに声かけたか?
9:デフォルトの名無しさん
07/05/02 02:46:05
GPO? PGO?
10:・∀・)っ-○◎●
07/05/03 03:46:08
11:デフォルトの名無しさん
07/05/03 14:12:12
ダンゴは糞だからイラネ
12:デフォルトの名無しさん
07/05/03 14:48:47
>>11
団子ちゃんが馬鹿にするな!
13:デフォルトの名無しさん
07/05/03 16:02:50
が?
14:・∀・)っ-○◎●
07/05/03 16:06:59
がががーが・がーがが
15:デフォルトの名無しさん
07/05/03 18:16:38
そりゃぁ、自分の基準にそって馬鹿だと思えば馬鹿にもするだろうよ。
団子じゃなくたってね。
16:デフォルトの名無しさん
07/05/03 18:30:39
int型の配列を特定の数値で埋めたいのですが、forループで一つ一つ回していく以外に
何か高速な方法はありませんか?
17:デフォルトの名無しさん
07/05/03 18:35:44
スレ違いの気がするが
・初期化
・memset
18:デフォルトの名無しさん
07/05/03 18:37:15
>>16
SSE2の使えるCPU用でいいなら、真っ当なコンパイラに適当なオプションを指定すれば、
勝手にベクタ化してくれる。
但し、極真っ当にループを書くこと。
19:・∀・)っ-○◎●
07/05/03 18:40:24
memset使えば、コンパイラによっては最適化でより高速な命令に置き換えてくれることもある。
たとえばx86なら要素数4の倍数個で16バイトアラインされてれば
for (i = 0; i < ARRAY_SIZE; i++) {
a[i] = foo;
}
↓
__m128i xfoo = _mm_set1_epi32(foo);
for (i = 0; i < ARRAY_SIZE; i+=4) {
mm_store_si128(&a[i], xfoo);
}
みたいな明示的ベクトル化は可能。
20:デフォルトの名無しさん
07/05/03 19:28:44
ビット演算についての質問です。
やりたいことは、最大値511 (2^9 - 1) で負の可能性がある
あるint型の値の値域を 0〜255 に絞りたいのです。
つまり、
x = (x <= 0 ? 0 : (x >= 255 ? 255 : x));
ですが、これを出来るだけ速くしたいのです。
(ちなみに、最終的に行いたいことはアドレス計算です)
一応自分なりに考えたのが、
x |= (0x100 - (x >> 8)); // 最大値を制限
x &= ~(0x100 - (x >> 31)) & 0xff; // 最小値を制限
または
x |= ((x >> 8) + 0x7f) ^ 0x7f; // 最大値を制限
x &= ((x >> 31) + 0x7f) ^ 0x80; // 最小値を制限
です。
最小値もある程度決めてしまって構わないのですが、
これ以上高速に値を得る方法はありませんか?
21:デフォルトの名無しさん
07/05/03 19:39:08
最小値がある程度小さいなら、最小値の制限は
x &= ~((unsigned)x >> 24);
でいいかと。
22:デフォルトの名無しさん
07/05/03 20:27:03
>>16 std::fill()
23:デフォルトの名無しさん
07/05/03 20:29:06
>>17,19
memset() は埋める値が 0 とか 0xff とかじゃないと使えないだろ。
24:デフォルトの名無しさん
07/05/03 22:17:18
>>21
それいいですね!
~の方が速そうなんですが、
最後は0xffでマスクしないとゴミがのる可能性があるので、
ちょっと変えて、((unsigned)x >> 24) ^ 0xff として使わせてもらいます。
ありがとうございました^^
25:デフォルトの名無しさん
07/05/03 22:19:57
あ、すまん。間違えてたわ。
その通り。
26:デフォルトの名無しさん
07/05/03 22:28:45
(unsigned)~x>>24
のほうが速そうに見える
27:デフォルトの名無しさん
07/05/03 22:33:07
なるほど。
28:デフォルトの名無しさん
07/05/03 23:22:19
>>26
たしかにそうですね。
と思い、コードを変更して計測してみました。
結果が、クロック単位でまったく同じだったのでおかしいと思い、
コンパイラの生成コードを見てみたのですが、、、
なんと、(((unsigned)x >> 24) ^ 0xff) が>>26とまったく同じようにコンパイルされてました
vc8すごい・・・
>>26さんもありがとうございました
29:デフォルトの名無しさん
07/05/03 23:46:17
コンパイラ<やれやれ、やっと俺の優秀さに気づいたか・・・
30:デフォルトの名無しさん
07/05/04 00:36:41
ダンゴさんに言わせれば、VCはクズだがな(笑)
31:・∀・)っ-○◎●
07/05/04 00:47:45
Pentium Pro時代の癖が抜けずに未だに
アドレッシングモード使うのを期待する場面で
ロード+レジスタ間オペレーションに展開する
VC++は駄目な子
32:・∀・)っ-○◎●
07/05/04 00:49:21
まあ、Intel謹製以外では一番マシだけどなw
33:デフォルトの名無しさん
07/05/04 01:17:32
C、C++の最適化について語るスレ -O2
いまさらだがスレタイはこんな感じのにスレばよかったのに。
34:デフォルトの名無しさん
07/05/04 12:45:30
AoSよりSoAの方が高速に動く理由を教えてください
35:デフォルトの名無しさん
07/05/04 20:37:59
C、C++の最適化についてダンゴ先生が篤く語るスレ
がいい
36:・∀・)っ-くコ:彡-
07/05/04 20:40:45
以下、団子に変わりましてイカがお送りします
37:デフォルトの名無しさん
07/05/05 17:06:49
関数の引数で、スタックのオーバーヘッドをなくす為に
const hoge_t& hoge なんて参照渡しが使われるけど
これってVC8とか今時のコンパイラでも意味ありますかね?
38:デフォルトの名無しさん
07/05/05 17:20:44
参照するとスタック使わなくなるわけでねえでがす
39:デフォルトの名無しさん
07/05/05 17:24:20
>>37
オブジェクトの作成を勝手に省略することは、
一部の例外を除いて規格上認められていないから、
今でも有効。
40:デフォルトの名無しさん
07/05/06 00:22:09
ま、ダンゴさんに言わせれば、VCはクズだがな(笑)
41:・∀・)っ-くコ:彡-
07/05/06 00:28:51
>>40はゴキブリかな
42:デフォルトの名無しさん
07/05/06 03:45:45
>>34
ものによるが、キャッシュが効きやすくなるか、ベクタ化しやすくなるか、ループの最適化をしやすくなる。
AoS の方がこれらに有効なこともあるので、ものによるとしか言えん。
43:デフォルトの名無しさん
07/05/08 00:40:06
グローバル変数Aを算出し、算出した関数内でAを参照したいときは、
@直読み
A算出時にローカル変数で一度算出しておき、それを参照(レジスタ参照で高速化を狙う)。Aは適当なところでローカル変数を代入
どちらがより良いソースコードになるでしょうか・・・。
@は見やすくてコード量も減りますが、いちいちRAMにアクセスしそうなので実行速度に懸念があります。
Aはローカル変数を用いることにより実行速度の向上を狙いますが、コード量の増加(ローカル変数増えまくり)や
オブジェクトサイズに懸念があります。
いまいちどちらにしたらよいかの判断が出来ませぬ・・・。
みなさまはどうされてます?
44:デフォルトの名無しさん
07/05/08 00:43:33
よくわからんが、関数・グローバル変数あたり、
待避と復旧用のコードが増えるだけでそ?
あと、レジスタに振られたローカル変数は消えるから。
45:デフォルトの名無しさん
07/05/08 00:50:12
>>44
レスどうもです。
「関数・グローバル変数あたり」が分かりませんでしたが・・。
ローカル変数を用いてレジスタアクセスを狙っても結局スタックに退避したら
変わらないってことでしょうか?
46:デフォルトの名無しさん
07/05/08 01:15:00
実測するしかないだろ。常識的に考えて。
47:デフォルトの名無しさん
07/05/08 06:09:18
>>43
俺様用語で抽象的なコードの質問されてもなぁ。
自分で最低限のコードを書いて、コンパイラに最適化させてアセンブリ出力見比べてみなよ。
まぁ、>46って結論が待っているけど。
48:デフォルトの名無しさん
07/05/11 06:47:42
最適化第一法則 最適化するな
最適化第二法則 まだ最適化するな
の意味の深さがまだ理解できていないと見えるな。
49:・∀・)っ-くコ:彡-
07/05/12 08:40:11
GCCってforループのiをインクリメントからデクリメントに変えるだけで
性能上がったりするよな
VC++なんかはループの最適化だけはアグレッシブだから
ほとんど気にする必要ないんだが
50:デフォルトの名無しさん
07/05/12 12:15:26
終了条件がたまたま 0 だったりするからじゃなくて?
51:・∀・)っ-くコ:彡-
07/05/12 12:29:07
0との比較のほうが命令数が少なくてすむんだよ
52:デフォルトの名無しさん
07/05/12 13:31:43
restrictedが使えるコンパイラってアルの?
53:デフォルトの名無しさん
07/05/12 13:33:48
あります。
54:デフォルトの名無しさん
07/05/12 13:35:58
>>53
bcc32を使っているのですが、うまくいきません
55:デフォルトの名無しさん
07/05/12 13:40:26
そんなもんに期待する方が間違っています。
56:デフォルトの名無しさん
07/05/12 13:40:26
あとiccもダメでした。
57:デフォルトの名無しさん
07/05/12 13:41:43
iccではちゃんと使えます。
58:デフォルトの名無しさん
07/05/12 13:42:04
そんなもんに期待する方が間違っています。
59:・∀・)っ-くコ:彡-
07/05/12 13:44:27
iccは9.1あたりから対応してるはず。VC2005コンパチだし。
60:デフォルトの名無しさん
07/05/12 14:29:43
そもそも restricted じゃなくて restrict だな。
GCC も余裕で使える。
61:デフォルトの名無しさん
07/05/12 14:30:50
そんなもんに期待する方が間違っています。
62:デフォルトの名無しさん
07/05/12 17:19:55
VC++は、2005から__restrictが導入されている。
63:デフォルトの名無しさん
07/05/12 23:41:50
__ かよ。
C++ でも使えるってことなのかな?
64:デフォルトの名無しさん
07/05/13 00:06:03
VCはc99じゃないからね。
65:デフォルトの名無しさん
07/05/13 01:21:12
ダンゴ先生に言わせればVCはクズだしなw
66:・∀・)っ-くコ:彡-
07/05/13 01:45:59
>>65は屑
67:デフォルトの名無しさん
07/05/13 03:40:23
烏賊自重しろ
68:デフォルトの名無しさん
07/05/17 16:38:10
長い数式の場合、複数の文に分けて書いた方が最適化しやすいのでしょうか、それとも一気に一つの文に詰め込んでしまった方がよいのでしょうか?
69:デフォルトの名無しさん
07/05/17 16:42:45
場合による
70:デフォルトの名無しさん
07/05/17 16:43:21
っ 実測
71:デフォルトの名無しさん
07/05/17 17:04:13
そういう最適化は尚早な最適化や、個人の好みでしかない事の典型的な例
72:デフォルトの名無しさん
07/05/17 17:29:12
オーバーロードしてるような時は
コピーコンストラクタが実行されないように
分けた方がいいやね。
73:デフォルトの名無しさん
07/05/17 17:39:47
>>68
先ずは読み易く書き、適切なコンパイルオプションでコンパイルし、そこが速度上のネックになっていないか測定し、
ネックになっているようならそこで初めて、そこを抜き出して両方のケースを測定してみることだ。
まぁ、コンパイラが適当に最適化してくれるから大差ないと思うよ。
74:デフォルトの名無しさん
07/05/17 21:24:07
ダンゴさんの締めのレスが待ち遠しいな
75:デフォルトの名無しさん
07/05/18 01:59:50
団子って良く呼ばれるけど、
書き込んだら書き込んだで叩かれるんだよな
76:デフォルトの名無しさん
07/05/18 02:04:33
呼ばれてしゃしゃり出て叩かれることを学習させないと。
赤子と同じ。
77:デフォルトの名無しさん
07/05/18 08:26:43
赤子みたいなレスだなw
78:デフォルトの名無しさん
07/05/18 11:36:25
赤子はこれから学習するが
団子は学習した結果
79:デフォルトの名無しさん
07/05/18 13:50:28
スキルの無い奴の粘着人格攻撃を受けられれば、コテも一流だな。
団子の圧勝か・・・。
80:デフォルトの名無しさん
07/05/18 20:13:30
団子は好きだけど思い込みが激しいから反芻してから発言して欲しい。
オレモナー
81:デフォルトの名無しさん
07/05/18 20:43:54
試しに >>80 を反芻してみた。
込みいからが発言して欲モ激しから反芻してい団しい。
オレ子は好きだけど思ナー
82:デフォルトの名無しさん
07/05/18 21:04:05
団子が負けたところを見たことがない
はっきり言って最強
83:デフォルトの名無しさん
07/05/19 00:29:20
逃げるが勝ちってか
84:デフォルトの名無しさん
07/05/19 00:30:36
糞壁と一緒だな
85:・∀・)っ-くコ:彡-
07/05/19 00:38:34
お塩先生に負けますた
矢田亜希子たん取られますた
86:デフォルトの名無しさん
07/05/24 20:42:26
>81
どういうアルゴリズムを適用するとその並びになるのか教えてくれ
87:デフォルトの名無しさん
07/05/24 20:58:46
反芻アルゴリズム
攪拌ではない
88:デフォルトの名無しさん
07/06/07 10:55:11
vectorは[]でアクセスできますが、これってメモリ上でも連続しているということでしょうか?
配列と比べても、実行速度は変わらないと考えてよいのでしょうか?
89:デフォルトの名無しさん
07/06/07 11:01:05
最新の仕様では連続してる事が保証されてた気がする。
ただ、それは別に [ ] でアクセスできるからという理由ではない。
こいつは演算子オーバーロードされてるから。
例えば deque なんかも [ ] でアクセスできるけど、
こいつはメモリ上の連続性は保証されてない。
90:デフォルトの名無しさん
07/06/28 02:32:29
>>88
vectorは連続している事が保証されているので、いざとなったら先頭アドレスを取り出して配列としてアクセスすることも出来るよ。
あと、配列の[]やvectorのoperator[]は境界チェックをしないけど、vectorのat()は境界チェックをするよ。知ってたらごめんね。
91:デフォルトの名無しさん
07/06/28 17:21:44
>>88
逆に言えば、添え字演算子[]で読み書きできるからといって、
メモリ上で要素が連続している保障があるとは限らない。
dequeとかmapとか。
92:デフォルトの名無しさん
07/07/15 14:57:49
>88の人気に嫉妬
93:デフォルトの名無しさん
07/08/03 20:43:46
Intel compilerのx64版を使っているのですが、
レジスタにある筈の値を何度もメモリに読みにいったり、
もう使わないローカル変数をメモリに書き込んだりしています。
ループの奥底なので許容できません。VTune で見てもボトルネックになって
いるようです。
深い理由があってのことででしょうか?
それとも、x64版の熟成が未完なのでしょうか?
32bit版との賢さの違いについてどんな印象をお持ちですか?
94:デフォルトの名無しさん
07/08/03 21:19:37
64bit版は知らんけど、32bit版もインテルが自分で言うほど
飛びぬけた性能でもないような…。
体験版で試して、俺のプログラムはVCに全敗したから、買う
のやめた。Linuxだと他に選択肢が無いのかも知れんけどね。
95:デフォルトの名無しさん
07/08/03 21:42:37
ウチの場合はICCのが何割か速かったよ。画像処理で。
GCCとVCと比較してもっとも早かった。
64bit版はさすがに知らないけど。
マルチコアならレジスタにある値だけだとあんまり信用できないからかね?
96:デフォルトの名無しさん
07/08/03 22:02:01
ポインタをdereferenceした値なんじゃないの
97:デフォルトの名無しさん
07/08/04 01:58:07
>>93
const付けられるところには全て付けてるよな?
関数ローカルのauto変数とか、クラスのメンバ関数(not変数)とかにも。
それでエイリアス問題とかが片付くから、割と変わるぞ。
98:デフォルトの名無しさん
07/08/04 02:10:28
エイリアス問題はconstじゃ解決しないぞ
restrictキーワードが要る
99:デフォルトの名無しさん
07/08/04 03:29:23
ん?
メンバ関数がconstなら、その関数内から見たらクラスのメンバ変数は皆const扱いだろ?
となると、複数のポインタor参照でメンバ変数を参照したり、キャッシュを持ったりしても実害が無いだろ?
変更がありえないんだから。
つまりエイリアスが発生しても、それが問題にならないケースがあるわけだ。
(グローバル関数経由の変更というものもあるので、確実じゃないけどな)
もちろん、クラスのメンバ以外を操作するならrestrictが必要だな。
それはおっしゃる通り。
100:デフォルトの名無しさん
07/08/04 12:12:12
constは、「プログラマが」変数を書き換えないという表明であって、
値が変化しないことの保証にはならない。
ポインタor参照経由の値は、
常にaliasの可能性があるとコンパイラはみなさなければならない。
というか、最適化のためのconstnessの判断はコンパイラがやることなので、
最適化フェーズではregisterキーワードよろしく無視されると考えていい。
と似たことを以前constでメシがナンタラというスレで書いた気がする。
101:デフォルトの名無しさん
07/08/04 13:00:20
こういうことかな・・・?
class A{
public:
int x;
void foo(int*) const;
};
main(){
A *a = new A();
a->foo(&a->x);
}
void A::foo(int* p) const
{
int x1 = x;
*p += 1;
int x2 = x; // x 読み直し
}
102:デフォルトの名無しさん
07/08/04 15:53:02
うーん、そういうケースも多いだろうけど
constがオプティマイザに無視されるということはないと思うぞ。
以前関わったプロジェクトで、constがろくについていなかったので
片端から付けた事があるんだよ。
結果リリースビルドのバイナリが大幅に変わってしまった。
速度的にはそれほどの向上は無かったのが残念だけど(ホットスポットは変わらなかった)
全体的にconstメンバ関数のインライン化が行われていた。
約1%ほどバイナリが肥大化したのはご愛嬌^^;
103:デフォルトの名無しさん
07/08/04 16:08:05
そりゃまたアホなコンパイラだな・・・
それにその例だと、速度かわらず、バイナリが増えてるんなら無意味じゃないか。
104:デフォルトの名無しさん
07/08/04 16:12:56
ホットスポットが変わらないから速度の有意差が出なかったのだろ。
105:デフォルトの名無しさん
07/08/04 19:43:09
>>102
そこまで言うならメンバ関数への const の有無で出力コードの変わるソースを
出してみて欲しい。
106:デフォルトの名無しさん
07/08/05 01:23:48
ちょっとやってみたが、短いサンプルだとconstの有無に関わらずインライン展開されて
結局同じになってしまうな……
まあこの場合「const の有無で出力コードの変わるソース」が存在することを
証明できればいいのだから、最適化オプションの調整を含めて
もうちょっと詰めてみる。
こっちもデスマ中なので何日かかるかもしれないが、期待しないで待ってろ。
107:デフォルトの名無しさん
07/08/05 01:29:31
必要なのは「出力コードが変わる」じゃなくて「速度向上に貢献する」だぜ
つか、なにもデスマ中にやらんでも(´・∀・`)
元気なときにやろうぜ
108:デフォルトの名無しさん
07/08/05 02:29:18
いや、>>105がそう言っているんでな。
とりあえず「constで変わりうる」ということを出しておこうかなと。
C/C++では完全な参照透過性を保証する構文が無いから、
コンパイラにとって論理レベルでの最適化は難しいだろうが、
不可能では無い事を明示したい。
まあ今日は寝る。おやすみ。
109:デフォルトの名無しさん
07/08/05 02:56:49
>>108
そこまでわかっていて不可能ではないと思う根拠はなんだろう?
楽しみにしてるよ。
110:デフォルトの名無しさん
07/08/06 22:23:24
今年プログラム初めてまだまだわからないことだらけで助けてほしいことがある。
複数のファイルより条件に合う行を抜き出して一つのファイルに出力するプログラムを作ったんですが
処理に結構時間がかかってしまいます。何とか速度向上させたいのですが何か良い方法はないでしょうか?
本当は自分でいろいろ試行錯誤してやりたいのですが分け合って時間が取れなくて書き込みました。
111:デフォルトの名無しさん
07/08/06 22:26:47
グレップツール使いな
112:デフォルトの名無しさん
07/08/06 22:35:17
>>110
秀丸つかっとけ
113:デフォルトの名無しさん
07/08/06 22:36:36
>> 93 です。
色々アドバイス頂きながら、返信せず申し訳ありません。
const はきちんと付ける主義です。
わざわざ、{} を追加して、スコープを絞っても、ローカル変数の
無駄な書き込みを止めさせることはできませんでした。
何となく、ICC x64のコンパイル結果って回りくどい気がするのです。
命令のレイテンシとかキャッシュ効率とか考慮された結果かな?
114:デフォルトの名無しさん
07/08/06 22:40:25
restrictについては言及ナシですか。
115:デフォルトの名無しさん
07/08/06 23:06:13
つーか、具体的なコードも出さずにあーだこーだ言われても
「あーそうですか」としか言いようがないなぁ。
116:デフォルトの名無しさん
07/08/08 23:24:43
>>114
何故か書き込み不能になった返信がさらに遅れました。
restrictを使っても、コンパイル結果が同じでした。
仕事絡みなのでコードを出せません。ご了承下さい。
ごく一部を出しても、実害はないと思いますがバレると
厄介なことになりますもので...
117:デフォルトの名無しさん
07/08/08 23:26:13
別にその仕事とは全く関係ないコードを書けばいいのに。
118:デフォルトの名無しさん
07/08/09 02:19:54
○○○は糞、だけど証拠は出せません
いい流れだ
119:デフォルトの名無しさん
07/08/09 03:19:58
constによる最適化を主張する俺が戻ってきましたよ
とりあえずサンプルを作るのは諦めました。そこで
既存のプロジェクトからメンバ関数のconstを外す ⇒ エラーが出たところだけconstに戻す
という手順で相違点を調べました。(バージョン管理ツールは便利だねえ)
>>102の環境はVC7.1でしたがライセンスの関係で問題があるので
今回の環境は別のプロジェクトのCodeWarriorです。
で、リリースビルドの結果は以下の通り。
全関数(メンバ関数でないものやライブラリも含む) 12256個
constメンバ関数 253個
検証時にconstを削除出来なかったメンバ関数 24個
const削除前のコードサイズ 2899400 bytes
const削除後のコードサイズ 2899084 bytes
constを付けた方がコードサイズが増える傾向がありますが、CodeWarriorの場合は
インラインされやすくなるという傾向はありませんでした。
また、極端にパフォーマンスが変化するということはありませんでした。
(づづく)
120:デフォルトの名無しさん
07/08/09 03:40:23
逆アセンブリで見られる具体的な差異としては
const有りだと分岐命令の後に来ている命令が
const無しだと分岐命令の前に来ている
という現象が所々に見られました。
いつ評価しても同じなら分岐の後で評価したほうが得、ということなんでしょうか。
(遅延評価に似てる?)
サンプルを上げようかと思ったけど、きわめて眠いのでまた今度。
明日か明後日までに適当なアップローダの紹介を希望。
ではおやすみなさい。
121:デフォルトの名無しさん
07/08/09 07:15:32
分岐命令をまたいで命令が移動するってのは、動作が変わってるような気がする。
よくわからんからサンプルが欲しいな。ろだ↓
URLリンク(kansai2channeler.hp.infoseek.co.jp)
122:デフォルトの名無しさん
07/08/09 10:42:03
ほい、上げておいた。
URLリンク(kansai2channeler.hp.infoseek.co.jp)
全部上げるわけにもいかんので加工してある。
詳細は添付のreadme.txtを読んでくれ。
じゃ俺は戦場に戻る。
123:デフォルトの名無しさん
07/08/10 09:31:04
>>122
リストファイル中のソースとの対応がずれてたり、命令数の違いでアドレス部が
ずれてたりしてるけど、本当に命令レベルの違いだけを抽出すると、2箇所だけになった。
--
const無し:
lw v1,-21056(v0)
addiu a0,v1,436
lw v1,436(v1)
const付き:
lw a0,-20672(v0)
lw v1,436(a0)
--
const無し:
lw v0,-21056(v0)
addiu v1,v0,436
lw v0,436(v0)
const付き:
lw v1,-20672(v0)
lw v0,436(v1)
--
124:123
07/08/10 09:54:07
2箇所いずれも app->CheckMenu() のところね。逆読みすると、
app 内のポインタが指す配列か構造体から1つ値を読み出してるって感じ
なんだけど、やっぱり CheckMenu() のソースが欲しいな。ダメ?
const無しのほうにある addiu の結果は使われて無いように見える。
あれ? const 付けたほうがコード増えるって言ってたけど、ここでは
1命令減ってるね。
125:123
07/08/10 10:03:26
const の有無で最適化に影響が出てるんじゃなくて、オーバーロードに影響が
出て処理が変わってるだけじゃないだろうか?
たとえば std::bitset::operator [] (size_t) なんかだと、 const 版は単に bool が
返るけど、非 const 版は代入もできるプロキシオブジェクトが返るのでかなり
違った処理になるはず。
126:123
07/08/10 10:31:24
あ、 addiu の結果はその後の sw で使われるみたい。
app のメンバオブジェクトについて const 版が int を返して、
非 const 版が int& を返すようなオーバーロードが使われてる予感。
んで int& だと続く書き込みに使いまわせるからレジスタに置かれた、と。
127:デフォルトの名無しさん
07/08/10 11:09:19
やっぱり、単純にはなんとも言えないという結論か。
128:デフォルトの名無しさん
07/08/10 21:42:46
いや、大方の予想通りメンバ関数の const は最適化の助けにはならないって結論だろう。
129:デフォルトの名無しさん
07/08/12 22:50:05
お待たせしました。一時帰宅しました。
辛辣なツッコミを期待していたんだけど、ちょっと物足りないかしら。
まあ、相手してくれてありがとう。
以下質問に対するごお返答。
>>122
CheckMenu()は以下のようなコードになっている。オーバーロードはされていない。
bool CApplication::CheckMenu(int n) { return (m_MenuStatus == n); }
ちなみにappはCApplication型のグローバル変数。constではない。
>>128
出力バイナリは違っているのに、そう言いきれるのはなぜ?
130:デフォルトの名無しさん
07/08/12 22:51:52
小林洋平
131:デフォルトの名無しさん
07/08/12 23:42:01
>>129
関数の中身を晒してくれてありがとう。そういうことなら、素の int 型メンバ変数の
読み取りについてコンパイラ内部で >>126 の言うオーバーロードと似たような扱いが
されているんだろう。
今回の例では const が無い場合に int& をキャッシュするために命令数が一つ
増えたとすると、前後の処理内容によってはその int& のキャッシュによって効率が
上がることも考えられる。いつでも const を付けたほうが効率が良いとは言えない。
今回の例で、コンパイラが const 無しの場合に const 付きの場合と同じコードを
吐いても何ら規格に違反しない。最適化の詰めが甘かっただけとも言える。
132:デフォルトの名無しさん
07/08/13 10:42:15
constは保守のための手助けみたいなもんだろ
mutableしてない変数に代入しようとしてたらエラー吐くだけの
133:デフォルトの名無しさん
07/08/13 14:57:53
gcc の _attribute((const)) みたいなもんがあればいいのかも。
・関数の戻り値が引数とインスタンスの内容にのみ依存する。
つまり、
class Test {
public:
int foo() __attribute__((const));
void bar() const;
};
Test T;
int a = T.foo();
T.bar();
int b = T.foo(); // int b = a; に最適化できる。
134:デフォルトの名無しさん
07/08/14 02:07:27
>>132
変数定義時の const はそうでもないよ。 const 付きで宣言された変数は
ポインタや参照を関数に渡した後でも、値が元のままであることを期待して
最適化してもいい。
これに対してポインタ・参照の指す先の型や、メンバ関数に付ける const は
ほとんどコード生成に影響しないという話。
135:デフォルトの名無しさん
07/08/14 02:10:47
>>133
それはダメでしょ。
T の宣言に const が付いてないので T.bar() の中で const_cast して
値を変更しても合法なはず。
136:デフォルトの名無しさん
07/08/14 02:59:32
intメンバ変数一個のstructで試してみたが、
>ポインタや参照を関数に渡した後
では読み直しをやってるなあ。
環境はVC8とgcc3.4.4(cygwin)
137:デフォルトの名無しさん
07/08/14 03:34:58
>>136
どんなソースで試したの?
以下のソースだと s に対する const によって読み直しが消えて return 10 に最適化される。
const 外すと当然メモリ上の s.x が読み出される。
struct S { int x; };
void f(struct S const* p);
int g(void)
{
struct S const s = { 10 };
f(&s);
return s.x;
}
138:137
07/08/14 03:35:31
あ、確認した環境は Cygwin gcc 3.4.4 の -O3 ね。
139:デフォルトの名無しさん
07/08/14 09:55:00
似せるとこういう感じ。gccは-O3、vc8は/Oxです。
struct S { S(int x_):x(x_){} int x; };
void f(struct S const * p);
int g(void)
{
struct S const s(10);
f(&s);
return s.x;
}
つーか分からないのは仕方ないか。ということで
struct S { S(int x_):x(x_){} int x; int getX() const { return x; } };
void f(struct S const * p);
int h(int);
int g(void)
{
struct S const s(10);
h(s.getX());
f(&s);
return s.getX();
}
vc8もgcc3.4.4も、分かってるんだか分かってないんだか分からないコードを吐く。
さらに、このコードの int x を const int x にすると、gccは読み直しをしなくなる。
これはsのconst修飾に依存しない。(あれれ?)
140:デフォルトの名無しさん
07/08/14 10:20:39
>>139
ほんとだ。これは期待はずれだなぁ。
コンストラクタ内での代入を許すために const として定義されたという情報が
途切れてしまっている、って感じ?
メンバのほうに const を付ければ代入を許すタイミングは無いから、 >>137 と
同様に最適化できる、と。
141:デフォルトの名無しさん
07/08/21 08:34:45
const 談義中に割り込み質問ですみません。
VTune で、Clockticks をサンプリングすると"No Samples were collected."
になってしまいます。
Sample After Value を変えろ、との記述を見つけて試しましたが、
うまくいきません。(他の event は収集できます)
対策をご存知の方はいらっしゃらないでしょうか?
142:デフォルトの名無しさん
07/08/21 21:48:51
>>141 です。自己解決しました。
使っていたのが一つ前のバージョンのVTune だったので、
quad core に対応していなかったようです。
最新版の体験版をインストールしたらうまくいきました。
それにしても、何のエラーメッセージも出ず、Clockticks
だけ収集できないとは、恐ろしい。
143:デフォルトの名無しさん
07/08/25 12:59:29
switchの場合分けにおいて、記述したcase以外は絶対にありえないと
コンパイラにヒント出す方法って無いですか?
分岐の先頭でcase以外を範囲外として弾くのが状況として
ありえないのでもったいないです。
環境非依存でもVC6,7,8限定の方法でもかまいません。
よろしくお願いします。
144:デフォルトの名無しさん
07/08/25 13:51:02
>>143
こういう場合だったら、
switch(hoge)
{
case 1:
//1の処理
case 2:
//2の処理
default:
//ここに来ることは絶対にない
}
こうすればいいんでないの?
switch(hoge)
{
case 1:
//1の処理
default:
//2の処理
}
145:デフォルトの名無しさん
07/08/25 13:58:11
>>143
環境非依存ではそんなものはない。
c++であれば、enum型を使うことで慮ってくれるコンパイラがあるかもしれない。
146:デフォルトの名無しさん
07/08/25 14:40:46
>>144
アセンブラコードを見てみたところ
1・範囲外チェック
2・テーブルジャンプ
という流れにコンパイルされていました。
case 1:
//1の処理
default:
//2の処理
これだとdefaultの処理+テーブルジャンプの処理になってしまって、
結果的に範囲外チェックしているのと負荷は変わらないようです。
>>145
enum試してみます。
ありがとうございました。
147:143
07/08/25 14:41:25
sage失敗すみません
148:デフォルトの名無しさん
07/08/25 14:51:29
VC7以降なら __assume を使え
149:144
07/08/25 15:11:09
>>146
なるほど。こちらが勉強させてもらいました。
確かに範囲外だったら大変だから、コンパイラとしてはチェックせざるをえないんだね。
150:デフォルトの名無しさん
07/08/25 15:28:49
>>143
>144の前者のケースなら、
switch (hoge)
{
case 1:
...;
case 2:
default:
...;
}
でいいんでない?
151:デフォルトの名無しさん
07/08/25 15:29:37
つーか、二項しかないのにテーブルジャンプにしか最適化できないコンパイラが蛸な希ガス。
152:143
07/08/25 15:41:13
>>148
__assumeが意図にかなっているようです。ありがとうございました。
153:デフォルトの名無しさん
07/08/25 20:23:00
>>143
gcc限定ならコメントでなんか記述すればコンパイラが理解してくれた気がする。
154:・∀・)っ-くコ:彡-
07/08/25 20:54:24
関数テーブル+__forceinlineじゃ駄目だったっけ
155:デフォルトの名無しさん
07/08/25 21:02:19
gccはassert()が__assumeと同じ動作したはず。
156:デフォルトの名無しさん
07/09/24 00:02:22
assert(0);だな
157:デフォルトの名無しさん
07/09/24 13:53:56
♪ ∧,, ∧ ♪
♪ ∧,, ∧´・ω・) 美脚♪
∧,, ∧´・ω・) )
♪∧,, ∧´・ω・) )っ__フ ♪ ∧,, ∧
∧,, ∧´・ω・) )っ__フ(_/ 彡 .∧,, ∧ )
(´・ω・) )っ__フ(_/彡 ∧,, ∧ ) )
(っ )っ__フ(_/彡 .∧,, ∧ ) ) Οノ
( __フ(_/彡 ∧,, ∧ ) ) Οノ ヽ_)
(_/彡 ( ) ) Οノ 'ヽ_)
( ) Οノ 'ヽ_)
(ゝ. Οノ 'ヽ_) ♪
♪ ミ ヽ_)
158:デフォルトの名無しさん
07/10/06 14:06:35
C++特有じゃないとは思いますが質問させてください。
ある処理をループしようと思っているんですが、その時に、
カーソルとして使用するポインタを(ローカル変数として)毎回宣言するのと、
あらかじめ外部で宣言したものを使いまわすのではどちらが高速なのでしょうか?
159:デフォルトの名無しさん
07/10/06 14:39:57
>>158
大丈夫、そんなもんは真っ先にコンパイラの最適化の餌食になるから。
それ以前に、ポインタで回すよりも配列参照で回す方が速いかも知れない。
いずれにしても、ケース・バイ・ケースだから実測するべし。
160:デフォルトの名無しさん
07/10/06 14:41:04
♪ ∧,, ∧ ♪
♪ ∧,, ∧´・ω・) 美脚♪
∧,, ∧´・ω・) )
♪∧,, ∧´・ω・) )っ__フ ♪ ∧,, ∧
∧,, ∧´・ω・) )っ__フ(_/ 彡 .∧,, ∧ )
(´・ω・) )っ__フ(_/彡 ∧,, ∧ ) )
(っ )っ__フ(_/彡 .∧,, ∧ ) ) Οノ
( __フ(_/彡 ∧,, ∧ ) ) Οノ ヽ_)
(_/彡 ( ) ) Οノ 'ヽ_)
( ) Οノ 'ヽ_)
(ゝ. Οノ 'ヽ_) ♪
♪ ミ ヽ_)
161:158
07/10/06 15:01:50
>>159
なるほど。コンパイラに頼れそうですね。
配列については任意の位置に追加、削除等の関係から使えませんでした。
ありがとうございました。
162:poooh ◆manko/yek.
07/10/06 16:10:39
グローバル変数は最適化に良くない。これ豆知識な。
163:デフォルトの名無しさん
07/10/06 17:34:59
グローバル変数は最適化に良い。これ豆知識な。
164:デフォルトの名無しさん
07/10/06 17:54:04
確かに、既存ソフトの高速化の仕事をしていると、グローバル変数があったら狙い目だとは思うけどね。
165:デフォルトの名無しさん
07/10/06 18:27:36
>>164
高速化の仕事ってどんな感じなの?
今の職場では高速化の効果が工数の割に合わないと言われることが多くて
バグ改修時についでに高速化する程度しかやらせて貰えない。
既存機能を維持しつつどうやって安全に高速化してるの?
グローバル変数触るなら単体テストだけじゃ足りないよね?
166:デフォルトの名無しさん
07/10/06 20:10:46
既存機能を維持しないでどうやって危険に高速化してるの?
そんなんだからやらせて貰えないんだぜw?
167:デフォルトの名無しさん
07/10/06 20:12:21
単体テストで完全に見えるスコープで、グローバル使いまくる馬鹿は沢山いる
168:164
07/10/06 21:00:33
高速化で受ける業務はソースで引き渡しだから、コード解析結果と単体テスト結果しか出さない罠。
169:165
07/10/06 21:36:19
>>168
高速化で受けた業務なら性能試験はやるんじゃないの?
単体テストしかしないなら関数単位の高速化なのかな? ライブラリ系?
参考までに、使ってる測定ツールとか教えてくれないかな。
それにしても、コード解析結果と単体テスト結果で話がつくとはな。
俺んとこだと結合試験と性能試験やらずに改修完了なんてまず了承されないよ。
170:デフォルトの名無しさん
07/10/06 21:53:07
そりゃぁ、「何」で金取っているかの違いだろ。
依頼主だって全部の環境晒せるような物ばかりとは限らんわけだし。
171:デフォルトの名無しさん
07/10/06 22:17:43
結合と性試験やらずに
172:デフォルトの名無しさん
07/10/07 21:26:42
単体テスト=手淫
173:デフォルトの名無しさん
07/10/11 07:30:27
♪ ∧,, ∧ ♪
♪ ∧,, ∧´・ω・) 美脚♪
∧,, ∧´・ω・) )
♪∧,, ∧´・ω・) )っ__フ ♪ ∧,, ∧
∧,, ∧´・ω・) )っ__フ(_/ 彡 .∧,, ∧ )
(´・ω・) )っ__フ(_/彡 ∧,, ∧ ) )
(っ )っ__フ(_/彡 .∧,, ∧ ) ) Οノ
( __フ(_/彡 ∧,, ∧ ) ) Οノ ヽ_)
(_/彡 ( ) ) Οノ 'ヽ_)
( ) Οノ 'ヽ_)
(ゝ. Οノ 'ヽ_) ♪
♪ ミ ヽ_)
174:デフォルトの名無しさん
07/10/17 08:10:23
for (int i=10;i--;)
{
//ループの中身
}
って
for (int i=0;i<10;i++)
{
//ループの中身
}
より高速?
175:デフォルトの名無しさん
07/10/17 10:40:19
>>174
上の方がループの回数が多いから遅い。
176:デフォルトの名無しさん
07/10/17 12:55:44
すみません
for (int i=0;i<9;i++)
{
//ループの中身
}
でした
177:デフォルトの名無しさん
07/10/17 13:16:29
>>176
>175は間違い。>174でループ回数は同じになっている。
で、どちらも同じ速度のコードになったよ(icc -fastで)。
実測したら、後者の方が気持ち速かった。と言っても、差は10msオーダーだけど。
--
for (int i = 0x7000 * 0x10000; i--;) func();
for (int i = 0; i < 0x7000 * 0x10000; i++) func();
--
178:デフォルトの名無しさん
07/10/17 13:32:58
速度は実測が基本。
179:デフォルトの名無しさん
07/10/17 15:04:30
>>177
ありがとう、やっぱりふつうに記述した方が、コンパイラにとってもいいようですね。
180:・∀・)っ-くコ:彡-
07/10/18 00:31:08
forよりdo-whileが速い。
まあ自動で最適化してくれるけど
181:デフォルトの名無しさん
07/10/18 10:54:47
/*1*/
for (i = 0; i < n; i++)
これと、誘導変数を使った
/*2*/
for (ii = -n; ii < 0; ii++)
i = n + ii;
それぞれについて、生成コードを予想
また実際の処理系に生成させたコードを評価せよ (n点)
182:デフォルトの名無しさん
07/10/18 12:17:32
変数の型が分からないと予想できねえよ。
183:デフォルトの名無しさん
07/10/18 12:38:28
nは正数?
184:デフォルトの名無しさん
07/10/18 12:41:36
クラスかもな。
185:デフォルトの名無しさん
07/10/18 13:05:00
宿題?
186:デフォルトの名無しさん
07/10/18 13:39:29
実行コストについてはダウンカウンタと大差ない感じ。
こりゃ使える。いただき。
a[i]みたいにiをインデックスで使う場面では
a[n+ii]に対して&a[n]==a+nがループ内不変になるね。
つかiは符号付き整数だろw
で、おれ何点?
187:519
07/10/18 13:41:59
for文の中身は?変数がintだとすると
for (i = 0; i < n; i++);
は i=n; という式に展開される可能性がある。
for (ii = -n; ii < 0; ii++) i = n + ii;
もnが定数ならば定数代入式に展開される可能性がある。
ていう最適化機能がgccにあったような…?記憶違い?
188:デフォルトの名無しさん
07/10/18 16:04:41
空ループの話で盛り上がって 参りました
189:デフォルトの名無しさん
07/10/18 16:18:58
全然
190:デフォルトの名無しさん
07/10/19 09:21:06
乱数が100個必要だとして、単にループで100回乱数を発生させるのではなく、
1つの乱数から、分割するなどして100個効率よく発生させることはできないでしょうか?
191:デフォルトの名無しさん
07/10/19 09:28:51
分割って何?
並列化するってこと?
100個乱数拾うだけならたいした変化は無いと思われ
192:デフォルトの名無しさん
07/10/19 09:43:07
使い道や欲しい乱数の範囲など具体的に
193:デフォルトの名無しさん
07/10/19 12:21:09
MTなら実装によっては624個の乱数が一度に得られる
でも内部的にはループだしな
194:デフォルトの名無しさん
07/10/19 18:51:21
>>190
64bitの乱数があったとしてそれをそれを8bit区切りに4つに分けて
8bitの乱数4つとして使えるかってこと?
乱数の質は悪くなると思うけど、どうだろ?
195:190
07/10/20 05:36:18
用途はモンテカルロシミュレーションです。
現在はMTを使っています。
計算精度は32bitのfloatでやっているのですが、乱数は64bitのdoubleなので、
それを単純に上位と下位に分けて、一回で2回分使えないかと考えています。
もうひとつ考えているのは、64bitで生成された乱数を、ローテートで1bitずつずらして
一回のMTで64個の乱数が生成できないかということです。
ただ、この場合、乱数の質が元のMTに対してどのようになってくるのかがわかりません。
196:デフォルトの名無しさん
07/10/20 05:45:19
MTやめてXorShift使うとか
197:デフォルトの名無しさん
07/10/20 06:46:44
>>195
少なくとも2番目の方法はいくない。
例えば一番左のビットが0の場合、左にローテートしたら元の数の2倍になる。
つまり64個の乱数の中に、大量のaとa*2が入り込む非常に膣の悪い乱数になるよ。
198:デフォルトの名無しさん
07/10/20 07:42:54
>膣の悪い乱数
乱れすぎw
199:デフォルトの名無しさん
07/10/20 08:45:07
>>195
最初の方法もダメ。
MTのdoubleは基本的に仮数部32bitなので分割した下の方は精度が腐る。
仮数部53bitの方は乱数を2個使っているし。
200:190
07/10/20 10:15:36
皆さんありがとうございます。
とりあえず、2^128-1周期のXorShiftを使ってみようと思います。
ところでXorShiftのseedのとり方ですが、オリジナルの文献では
x=123456789,y=362436069,z=521288629,w=88675123;
となっていますが、たとえば、x=1,y=2,z=3,w=4;とすると最初の
数十個は
2061
6175
4
8224
4194381
8396986
8388750
25174430
8652983179
25875070649
8636205711
60369541016
17600805477257
35210146488062
52785194351115
70428979519260
36239912164446735
ように非常に悪い乱数系列になってしまいます。
最初の数百個を捨てればよいのかもしれませんが、seedの選び方には何か決まりがあるのでしょうか?
201:デフォルトの名無しさん
07/10/20 13:19:11
>>190
sineくれくれ厨
202:デフォルトの名無しさん
07/10/20 14:14:15
お前がsine
203:デフォルトの名無しさん
07/10/20 15:24:11
>>200
質が悪いって言うけど、どの一部を取り出してもそういった偏りが全く無いほうが質が悪いでしょ。
固定の種にしたいなら好きなだけ選びなよ。
204:デフォルトの名無しさん
07/10/20 15:28:19
つーか擬似乱数スレでやれよ
205:デフォルトの名無しさん
07/10/20 15:58:23
sine、cosine
206:デフォルトの名無しさん
07/10/20 17:18:59
tangent
207:デフォルトの名無しさん
07/10/20 19:44:18
cosecant
208:デフォルトの名無しさん
07/10/21 00:53:23
俺には >>200 の乱数列のどこが質が悪いのか分からん
誰か説明してくれ
209:デフォルトの名無しさん
07/10/21 12:35:59
>>208
このスレは馬鹿なお前のためにあるんじゃない
210:デフォルトの名無しさん
07/10/21 19:33:52
>>200
乱数の種で複数の値とるとき
互いに素ってのと2の累乗を自分は使わないようにしているけど…
根拠がない。それに小さすぎる値も使わないようにしている。(1とか2とか…)
211:デフォルトの名無しさん
07/10/23 01:51:46
>>200
void srand_xor128(void){ w^=(unsigned)time(0)*1812433253; }
とかwだけ変更すればたぶんおk。心配なら最初の十万個位捨てたら。
212:デフォルトの名無しさん
07/11/07 04:00:14
PSP用ゲームのVCとGCCの両用ソースなんですが
関数内でstaticな配列を使ってはならないという社内ルールが付けられているんですが
理由わかります?
void hoge()
{
static const int array[100] = { 123, 456, 789, 123, 456, 789, };
,,,,
}
このようなstaticは駄目で
const int array[100] = { 123, 456, 789, 123, 456, 789, };
にしろということなのです。
メモリが厳しいらしいのですが、これで本当に節約になるんでしょうか。
213:デフォルトの名無しさん
07/11/07 04:34:13
>>212
実際にコンパイルしてアセンブリ出力を眺めてみれば?
前者は静的領域に確保されることが保障されていて消えることは多分ないが、
後者は最適化で消える可能性がある。
しかし、後者は静的領域からスタックにコピーする最悪なコードになるかもしれない。
それはさておき、100要素指定しておいて6個しかないと激しく無駄だと思う。
214:デフォルトの名無しさん
07/11/07 04:36:44
>>212
メモリの節約にはならないだろう。
一般的な実装を予測すると、 static をはずしてもスタックに確保された配列を
初期化するためのコピー元となる配列が作られてしまう。この初期値の配列が
static をつけた場合に確保される実体と同等のはずなので、 static をはずすと
スタックの領域と初期化用コピーの処理時間が余計に増えるだけになる。
動作上の違いは、再帰呼び出ししたときに配列のアドレスが別物になるかどうか、
という点しかないはず。
はっきり言って逆効果だろう。そのルール決めた人に理由を問い詰めたほうがいい。
非 const な変数に限ってローカル static を禁止するのなら、メンテナンス性の観点から
まだ理解できる。
215:デフォルトの名無しさん
07/11/07 04:56:45
次に静的記憶域期間(static)です。
こちらは宣言されている場所にかかわらずプログラムの開始直前にメモリを確
保し初期化します。初期化を忘れた場合値は0になります。
また、確保された領域はプログラムが終了するまで保持されるので関数の終了
時に値が消えることがありません。2回目以降関数内のstaticオブジェクトを
利用するときは前回の値から始まります。
次ページ最新レス表示スレッドの検索類似スレ一覧話題のニュースおまかせリスト▼オプションを表示暇つぶし2ch
5001日前に更新/166 KB
担当:undef