2012-10-10 12 views
5
  1. llvmまたはgccコンパイラを使用すると、結果のマシンコードの点で次の2つのコードブロックに違いはありますか?
  2. いつこの最適化が実際に価値があるのですか?

は、最適化されていません:forループの条件を事前計算する価値はありますか?

for (int i=0; i<array.count; i++) { 
    //do some work 
} 

は最適化:

int count = array.count; 
for (int i=0; i<count; i++) { 
    //do some work 
} 

EDIT:私はarrayは不変であるとarray.countがループの実行中に変化しないことを指摘しなければなりません。

+2

コンパイラが最適化を行う可能性が高いため、しばしば必要ありません。しかし、確かな唯一の方法は、両方の方法と測定をテストすることです。生成されたマシンコードに関しては、簡単に自分自身をチェックすることができます。clangとgccの両方にアセンブラファイルを出力するフラグがあります。何もない場合はいつでも実行ファイルを逆アセンブルできます。 –

+1

この場合、オブジェクトに送られるメッセージがあります。私はコンパイラがそれに干渉するのではないかと疑うので、私の推測では、各繰り返しで 'count'メソッドが呼び出されると思います。しかし、それはおそらく非常に安い呼び出しです。この特定の場合の最善の方法は、配列の高速列挙を使用することです。 – Guillaume

+3

"配列は不変で、array.countは変更されません" - "不変"がコンパイラが理解できるプロパティであるかどうかはわかりませんが、最適化の目的では ' array.count'が変更された場合、コンパイラが 'array.count'が変更されないことを自身が証明できるかどうかは重要です。 –

答えて

3
  1. 本当に自分で確認する必要があります。私の推測では、ですが、発行されるコードに違いがありますが、コンパイラとコンパイラのオプションに依存する可能性があり、確かにarrayの定義に依存する可能性があります。
  2. ほとんどの場合、array.countの評価は、「ある仕事」に比べてほとんど重要ではないという前提で行われます。ただし、これを測定する方法は、プロファイラ(またはそれに相当するもの)を使用して、プログラムのランタイムのどの部分がそのコード行に費やされているかを観察することです。プロファイラが正確であれば、それはであり、ほとんどです。あなたはそれを変更して得ることができます。

たとえば、array.countは本当に遅いものですが、常に同じ結果が返ってくることはわかっていますが、コンパイラはそのことを知らないとします。その後、それを手動で持ち上げる価値があるかもしれません。例としてstrlenが使用されます。あなたと私はsome_functionが0を返すことはありませんことを知っている

char some_function(char a) { 
    return (a * 2 + 1) & 0x3F; 
} 

for (int i = 0; i < strlen(ptr); ++i) { 
    ptr[i] = some_function(ptr[i]); // faster than strlen for long enough strings. 
} 

、との、したがって長さ:それはstrlen実際実際には遅いが、彼らがする必要があるよりも遅くなる可能性が高い例を製造しやすい頻度debateableです文字列は決して変化しません。コンパイラはsome_functionの定義を見ることができないかもしれません。そして、たとえそれが見えても、そのゼロ以外の返り値が重要であることを定義では理解できないかもしれません。

1

スティーブ・ジェソップの回答が良いです。私はただ追加したい:

個人的に、私は常に最適化されたバージョンを使用します。ループからすべての定数コンポーネントを削除するのは、私の良いプラクティスのセットにすぎません。それはあまり仕事ではなく、コードをきれいにします。 「時期尚早の最適化」ではなく、問題やトレードオフを導入しません。デバッグが容易になります(ステップ実行)。潜在的にコードを高速化する可能性があります。だから、私には納得のいくものです。

関連する問題