最適化コンパイラとは何ですか?

画像








現在、市場にあるほとんどすべてのコンパイラは最適化されています。 つまり プログラマーによって書かれたコードを機械語に変換するだけでなく、パフォーマンスやボリュームの面でも改善できます。



しかし、コンパイラはコードを改善するために正確に何ができますか?



まず、次の3つのことです。

  1. コンパイラはプログラミング言語ツールを効果的に実装できます
  2. プログラムが実行される機器の機能を最大化できます
  3. また、プログラマーによって実装されたアルゴリズムの欠点のいくつかを排除します。


これらの可能性のそれぞれをより詳細に検討しましょう。



最新のプログラミング言語は、アルゴリズムを表現するための強力なツールをプログラマに提供します。 ただし、これらのツールがコンパイルレベルで十分にサポートされていない場合、高レベル言語の利便性により、パフォーマンスが大幅に低下する可能性があります。



C ++での仮想関数呼び出しの例を考えてみましょう。

class A { public: virtual int func () { return 5; } }; class B : public A { public: virtual int func () { < >; } }; A* ptr = new A(); int value = ptr->func();
      
      







ここには、AとBの2つのクラスがあります。クラスAには最も単純な仮想関数が含まれており、常に定数(数値「5」)を返します。 クラスBはクラスAを継承し、仮想関数をオーバーライドするため、いくつかの複雑な計算を実行します。



仮想関数のメカニズムがコンパイラで十分にサポートされていない場合(更新:この場所では、一部のコンパイラが他のコンパイラよりもC ++ツールをサポートしているわけではありません。エントリへのコメントで例の詳細な分析を参照してください)、コンパイラは式int value = ptr-> func();で呼び出される仮想関数のバージョンを理解できません。 ただし、優れたコンパイラーは、最も単純な関数を呼び出す必要があると判断できます(つまり、クラスAのインスタンスのみがptrポインターを介してアドレス指定されます)。 つまり、最後の式は次のように最適化できます。int value = 5;



上記の例は、プログラミング言語の絶対的な有効性について話すことは意味がないことも示しています。 コンパイラでのこの言語の特定の実装は常に暗示されるべきです。 たとえば、「C ++またはJavaのどちらが速いですか?」という質問は完全に正しいわけではありません。 正しく実装されていないC ++は、優れたJava実装を失う可能性があります。逆に、C ++の優れたコンパイラは、悪いJavaコンパイラに大きな有利なスタートを切ることができます。



したがって、アルゴリズムの表現における現代のプログラミング言語の力は、コンパイルレベルでこれらの言語の効果的な実装がある場合にのみ正当化されることがわかります。



ここで、最適化コンパイラがプログラマに提供する2番目の機会、つまりハードウェアリソースの使用を最大化する能力について考えてみましょう。



再び現代のプログラミング言語に目を向けましょう。 C ++、Java、Pascalなどの言語を使用することで、プログラマーは可能な限りアルゴリズムの作成に集中できます。 これは、言語が、プログラムが実行される機器の機能をプログラマーから「隠す」という事実により、主に達成されます。 ハードウェアリソースの最も完全な使用は、最適化コンパイラのタスクです。



ハードウェアリソースの効率的な配布の問題は、高水準言語の使用の結果だけではないことに注意してください。 プログラマーがアセンブリ言語で記述し、彼が記述しているハードウェアの機能に完全に精通している場合でも、自動ツールを使用しないと解決するのが非常に難しい問題があります。



例として、Intel Itaniumマイクロプロセッサに存在するループパイプライン化を検討してください。 パイプライン処理のおかげで、Itaniumプラットフォームでは、1サイクルの複数の反復を並行して実行できます(図を参照)。



Intel Itanium




ソフトウェアのパイプライン化



ここで、時間t1で、サイクルの最初の反復の実行が開始されます。 時間t2で、まだ最初の反復を実行するプロセスで、同じサイクルの2番目の反復の実行が開始されます。 また、時刻t3以降、同じサイクルの3つの反復がすでに同時に実行されています。



このようなパイプラインのリソース計画は、かなり複雑な「機械的な」タスクです。 プログラマーがアセンブリ言語プログラミングのドックであっても、最適化コンパイラーが一瞬で対処するタスクに膨大な時間を費やす必要はありません。



最後に、最適化コンパイラの3番目の利点に進みましょう。 このようなコンパイラは、プログラマのアルゴリズムに「ストローク」を導入する可能性があります。 そして時には非常に重要な「タッチ」。



もちろん、コンパイラーはアルゴリズムを根本的に変更することはできません(少なくとも、最新のコンパイラーはまだこれから非常に遠いです)が、いくつかの非最適化を削除する能力はかなりあります。 時々、そのような準最適性の除去は、プログラムの加速につながる場合があります。



例を考えてみましょう。

 for (i = 0; i < n; i++) {  = e * f; a[i] = c * i; }
      
      







このCコードのフラグメントでは、ループの各反復で変数「c」が計算されます。 この場合、サイクル内の変数「e」も変数「f」も変更されません。 したがって、変数「c」をループで計算する必要はありません。 ループ外で一度計算すれば十分です:

  = e * f; for (i = 0; i < n; i++) { a[i] = c * i; }
      
      







このバージョンのサイクルは、以前のバージョンよりもはるかに高速に動作します。



上記の変換は、最も単純な最適化コンパイラーでも実行できます。 ただし、コンパイラファミリの最高の代表者のみが利用できる、はるかに複雑な変換の例を提供できます。



本文に示されている例は、最適化コンパイラは、高価な人的資源を引き付けるのが非合理的である作業の一部をプログラマーのために行うように設計されていることを示しています。 さらに、コンパイラの信頼性が高く、「スマート」であればあるほど、プログラマの仕事からより多くの利益を引き出すことができます。



All Articles