2011-10-20 20 views
8

私はJITコンパイラにインライン関数呼び出しのすべての最適化をさせることをベストプラクティスと結論づけるいくつかの記事と質問/回答を読んだ。意味をなさないJITコンパイラは不要な変数宣言を最適化(インライン化)しますか?

インライン変数宣言はどうですか?コンパイラはこれらも最適化していますか?

 Dim h = (a + b + c)/2  'Half-Perimeter 

     If maxEdgeLength/(Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) <= MaximumTriangleAspectRatio Then 
      'Do stuff here. 
     End If 

これよりも優れた性能を持っている:もちろん

 Dim perimeter = a + b + c 'Perimeter 
     Dim h = perimeter/2  'Half-Perimeter 

     Dim area = Math.Sqrt(h * (h - a) * (h - b) * (h - c)) 'Heron's forumula. 
     Dim inradius = area/h 
     Dim aspectRatio = maxEdgeLength/inradius 

     If aspectRatio <= MaximumTriangleAspectRatio Then 
      'Do stuff here. 
     End If 

私は後者を好む、それは読みやすく、デバッグだが、私は余裕がないので、これはされますされ

それが存在すればパフォーマンスの低下。

注:私はすでにこのコードをボトルネックと認識しています。早すぎる最適化についてのレトルトの必要はありません。 :-)

+6

余分な20バイトのRAMを用意する余裕はありませんか?これは、特にこのコードが繰り返し実行されるたびに、同じ20バイトごとに同じように、アプリのパフォーマンスを左右することはほとんどありません。 –

+0

MSILへの翻訳中に、この種の最適化のためのコンパイラ(JITではありません)が "責任を負う"でしょうか? (そして、MS C#コンパイラがどの程度最適化しているかは、どのような場合でも可能です。)どんな場合でも、相対論的な環境*でベンチマークすることは、より速く、かつ、ある程度「確実に知る」唯一の方法です。 –

+4

あなたはこの質問に答えることができる唯一の人です。あなたは両方の方法でコードを書いています。両方の方法で実行し、タイミングを測定すると、どちらが速いかがわかります。ジッタが行うこととしないことは無関係です。ジッタが何をしているかを知ることは、「どちらが速いの? –

答えて

16

名前を持つ一時変数は問題ではありません。

しかし、その不等式を大幅に最適化することができます。

あなたのコードは次の通りであった:平方根で

If maxEdgeLength/(Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) <= MaximumTriangleAspectRatio Then 

乗算両側、(平方根が負の数を返すことができないため、不等式が保存される)の分割を排除:

If maxEdgeLength <= (Math.Sqrt(h * (h - a) * (h - b) * (h - c))/h) * MaximumTriangleAspectRatio Then 

今、正方形その高価な平方根を排除するために両側:

If maxEdgeLength * maxEdgeLength <= h * (h - a) * (h - b) * (h - c)/h/h * MaximumTriangleAspectRatio * MaximumTriangleAspectRatio Then 

キャンセル、m最終的にはh

If maxEdgeLength * maxEdgeLength * h <= (h - a) * (h - b) * (h - c) * MaximumTriangleAspectRatio * MaximumTriangleAspectRatio Then 

これは非常に高速です。この計算を繰り返す場合は、この式の一部の結果をキャッシュしてさらに改善することを検討してください。

数式を説明するためにコメントを使用します。ボトルネック関数でMath.Sqrt呼び出しを取り除くことは、簡単な形式で表現を書く価値があります。ところで

+1

(ちょっと)コメントを使うのではなく、計算をスタンドアローン関数にリファクタリングします。そういうコードでは長すぎます。 *必要に応じて機能することを説明してください(特に、上で行われた変換を説明してください)。 –

+6

+1は、最適化がコードまたはコンパイルではなくアルゴリズム自体ではないことを識別するためのものです。 –

5

、ちょうど悪魔の提唱者を再生するには、また、私はこれを指摘したかった:全体の機能の

JITのインライン化は、計算の複雑さをMSILのバイト単位の長さを見て、ではありません。ローカル変数を追加すると(そして、JITがそれらを登録することを期待して)、関数全体のインライン化の候補にならないほどMSILのサイズが大きくなる可能性があります。

これは、Math.Sqrtの不要な使用と大きな違いはありませんが、可能性もあります。 Eric Lippertが言ったように、あなたは実際に測定することによってもっと知るでしょう。ただし、そのような測定はプログラムの特定の実行に対してのみ有効であり、JITの動作をしばしば調整する異なるプロセッサまたは将来のバージョンの.NETランタイム(サービスパックを含む)には一般化されません。ですから、最適化のための分析的かつ経験的なアプローチを必要としています。

+1

あなたは優れたポイントを作るベン;例外的な場合を除いて、実際には「最適化」というものはありません。いわゆる「最適化」は、実際には私たちが望むトレードオフですが、そうではないかもしれません。その計算で使用できるレジスタの数が少ない場合は、この計算でより多くのレジスタの使用を交換し、より速くする必要があるものを選択したことを願ってください。または、メモリ使用量をより少ない時間で交換し、後でキャッシュミスを起こさないようにしてください。等々。 –

+0

@EricLippert:はい、絶対最適化にはトレードオフが伴います。しかし、それは私が作っている点の横にある。 JITコンパイルを使用すると、変更されたオプティマイザアルゴリズムが適用され、同じMSIL入力で異なるトレードオフになります。伝統的なAOTネイティブコンパイラであっても、同じ命令シーケンスは、異なるCPI特性を有する異なるプロセッサ上で異なって実行することができる。 –

関連する問題