9

レガシーコード、ライブラリコード、またはサンプルコードを自分のコードベースに統合するときに、ソースコードを再ハッシュすることで、時間を無駄にし、タイプミスのリスクを回避する方法を知りたいです。

画像処理のシナリオに基づいた簡単な例を挙げれば、私が何を意味しているのかがわかるかもしれません。

私が次のようなコードスニペットを統合しているのを見つけるのは実際には珍しいことではありません:

for (unsigned int y = 0; y < uHeight; y++)
{
    for (unsigned int x = 0; x < uWidth; x++)
    {
        // do something with this pixel ....
        uPixel = pPixels[y * uStride + x];
    }
}

時間が経つにつれて、私は不要な計算を内側のループから移動したり、接尾辞の増分を接頭辞に変更したりすることに慣れてきました...

for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned int uRowOffset = y * uStride;
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = pPixels[uRowOffset + x];
    }
}

または、行ごとにポインタ演算を使用する場合があります...

for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned char *pRow = pPixels + (y * uStride);
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = pRow[x];
    }
}

...または行と列で...だから私はこのようなものになります

unsigned char *pRow = pPixels;
for (unsigned int y = 0; y < uHeight; ++y)
{
    unsigned char *pPixel = pRow;
    for (unsigned int x = 0; x < uWidth; ++x)
    {
        // do something with this pixel ....
        uPixel = *pPixel++;
    }

    // next row
    pRow += uStride;
}

さて、最初から書くときは、自分の「最適化」を習慣的に適用しますが、コンパイラーも次のようなことを行うことを認識しています。

  • 内側のループから外側のループへのコードの移動
  • 接尾辞の増分を接頭辞に変更する
  • 私が知らない他の多くのもの

このように動作するテスト済みのコードをいじるたびに、時間のかかるだけでなく、指のトラブルなどでバグが発生するリスクもあります(上記の例は簡略化されています)。 )。「時期尚早の最適化」や、より優れたアルゴリズムなどを設計することでパフォーマンスを向上させる他の方法を知っていますが、上記の状況では、より大きなパイプラインタイプのアプリで使用されるビルディングブロックを作成しています。非機能要件が何であるかを予測するので、制限時間内(つまり、コードの調整に費やす時間)内で合理的である限り高速でタイトなコードが必要です。

ですから、私の質問は、「最新の」コンパイラーによって一般的にサポートされているコンパイラーの最適化をどこで見つけることができるかということです。Visual Studio 2008と2012を組み合わせて使用​​していますが、IntelのC /C++コンパイラなどの代替手段との違いがあるかどうかを知りたいと思います。誰かが洞察を流したり、有用なWebリンク、本、その他の参考資料を教えてくれますか?


私の質問を明確にするためだけに 編集

  • 上で示した最適化は単純な例であり、完全なリストではありません。コンパイラがとにかくそれを行うので、これらの特定の変更を行うことは(パフォーマンスの観点から)無意味であることを私は知っています。
  • 私は特に、使用しているコンパイラーによってどのような最適化が提供されるかについての情報を探しています。
4

3 に答える 3

16

例として含める最適化のほとんどは、時間の無駄になると思います。優れた最適化コンパイラは、これらすべてを実行できるはずです。

私は実際的なアドバイスとして3つの提案を提供することができます:

  1. 実際のデータを処理する実際のアプリケーションのコンテキストでコードをプロファイリングします。できない場合は、最終的なシステムを厳密に模倣すると思われるいくつかの合成テストを考えてください。
  2. プロファイリングを通じてボトルネックであることが実証されたコードのみを最適化します。
  3. コードの一部を最適化する必要があると確信している場合は、ループから不変式を因数分解するとパフォーマンスが向上すると思い込まないでください。常にベンチマークを行い、オプションで生成されたアセンブリを調べて、さらに洞察を得ます。

上記のアドバイスは、すべての最適化に適用されます。ただし、最後のポイントは、特に低レベルの最適化に関連しています。メモリ階層と帯域幅、命令パイプライン分岐予測SIMD命令の使用など、関連するアーキテクチャの詳細が多数含まれているため、これらは少しブラックアートです。

ターゲットアーキテクチャについて十分な知識を持っているプログラマーライターに頼るほうが、ターゲットアーキテクチャを巧みに操るよりも良いと思います。

時々、プロファイリングを通して、手作業で物事を最適化する必要があることがわかります。ただし、これらのインスタンスはかなりまれであり、実際に違いを生むものにかなりのエネルギーを費やすことができます。

それまでの間、正しく保守可能なコードの記述に集中してください。

于 2013-03-23T08:34:56.047 に答える
0

C / C ++コンパイラの最適化について何を想定できますか?

可能な限り、最適化されたコードで機能またはパフォーマンスのいずれかの問題が発生する場合を除いて、最適化とデバッグをオフにします。

Mordernコンパイラには、コードを最適化するためのさまざまな戦略があります。特に、並行プログラミングを行っている場合や、 OMPBoostTBBなどのライブラリを使用している場合はそうです。

コードが正確にマシンコードに変換されたことを気にする場合は、コードを逆コンパイルしてアセンブリを観察することをお勧めします。

手動で最適化を行うための最も重要なことは、予測できない分岐を減らすことかもしれません。これは、コンパイラーが行うのが難しいことです。

最適化に関する情報を探したい場合は、SOに関する質問がすでにあります。

最適化オプションには、それぞれが何を最適化するかについての説明があります。

そして、最適化の戦略と手法について何かがあります

于 2013-03-23T09:50:15.387 に答える
0

直接的な答えを得るよりも、質問の前提を再考する方がおそらく役立つと思います。

なぜこれらの最適化を実行したいのですか?あなたの質問から判断すると、具体的なプログラムをより速くすることだと思います。その場合は、次の質問から始める必要があります。このプログラムを高速化するにはどうすればよいですか。

その質問には非常に異なる答えがあります。まず、アムダールの法則を考慮する必要があります。これは通常、プログラムの1つまたは2つの重要な部分を最適化することだけが理にかなっていることを意味します。他のすべてはほとんど問題ではありません。プログラムのこれらの部分を見つけるには、プロファイラーを使用する必要があります。この時点で、プロファイラーを使用する必要があることをすでに知っていると主張するかもしれません。ただし、私が知っているほとんどすべてのプログラマーは、コードをプロファイリングする必要があることを知っていても、プロファイリングを行いません。野菜について知ることは、野菜を食べることと同じではありません。;-)

ホットスポットを見つけたら、解決策にはおそらく次のものが含まれます。

  1. アルゴリズムを改善して、コードの作業を減らします。
  2. キャッシュパフォーマンスを改善するためのメモリアクセスパターンの改善。

繰り返しになりますが、プロファイラーを使用して、変更によってランタイムが改善されたかどうかを確認する必要があります。

詳細については、Googleのコード最適化および同様の用語を使用できます。

本当に真剣になりたい場合は、Agner Fogの最適化マニュアルコンピュータアーキテクチャ:定量的アプローチも参照してください。必ず最新版を入手してください。

また、マイクロ最適化シアターの悲しい悲劇を読むこともできます。

于 2013-03-23T13:33:11.943 に答える