GCC4.7やVS12などの最新のコンパイラを使用して最新のC++でインラインアセンブルを使用すると、何かメリットがありますか?たとえば、ベクトル化といくつかの小さな最適化のために?それとも、それはただのいたずらであり、最新の最適化コンパイラでは、どのスコープでもそれを使用しても何も得られませんか?
4 に答える
インラインアセンブリを使用すると、コードアーキテクチャが固有になります。のような場合でも、vectorization
このコードを実行するターゲットがこれらの特別な/拡張された命令セットをサポートする必要があるという事実に依存するようになりました。
そして、誰かがあなたのコードをからに移植しようとするx86
とARM
、彼らはそれで苦労するだろうとしましょう。
ターゲットがSSE2やSSE3などのベクトル命令セットをサポートしているかどうかを検出し、最適化されたコードを実行し、拡張命令セットをサポートしていないターゲットで実行されるフェイルセーフコードを配置できるメカニズムを用意することをお勧めします。
たとえば、Linuxカーネルは、arch
ディレクトリの下にあるすべてのアーキテクチャ固有のコードを抽象化し、異なるアーキテクチャに対して同じ関数の実装があります。コードが複数の異なるアーキテクチャで実行される可能性があることがわかっている場合は、独自の抽象化を考え出すことで同様のことを行うことができます。
多くのものと同様に、それは異なります。
作成する可能性のあるほとんどのコードでは、インラインアセンブリは役に立たない可能性があります。最新のコンパイラはかなり賢く、通常、少なくともあなたが書くことができるものと同じくらい良いコードを生成します。(そして、彼らはあなたがそれを書いてデバッグするよりもかなり速くそれを生成するでしょう。)
ご想像のとおり、例外は特定のベクトルコードの記述です。一部のコンパイラは特定のループをベクトル化しようとしますが、熟練した人間ほどうまく機能しません。特定のアプリケーション(DSP、ビデオエンコーディングなど)では、これにより大きな違いが生じる可能性があります。ただし、これには、コーディングしているプロセッサの詳細な知識が必要です。不適切に記述されたベクトルコードは、コンパイラが思い付くスカラーコードよりもパフォーマンスが低下することがよくあります。
結論:インラインアセンブリを作成する必要があると信じる十分な理由がない限り、それは避けてください。
一般的に、探しているのは、特定の命令を薄くラップする組み込み関数です。
これにより、インラインアセンブリが提供するのと同程度の制御を維持しながら、C++の型安全性を放棄することなくベクトル命令などにアクセスできます。本質的に、組み込み関数では、使用する命令を選択しますが、コンパイラーはレジスタ割り当てを実行します。
これに対する答えは、英語の表現「弦の長さ」に少し似ています。実際に弦全体をほどかなければ、簡単に答えることはできません。ここでも同じですが、コードが実際に何をするのかを知らなければ、メリットがあるかどうかはわかりません。
私の一般的なアプローチは、CまたはC ++を使用してコードを記述し、コンパイラーの機能を確認することです。[定義されているものが何であれ]十分に高速であれば、他に何もする必要はありません。速度が不足している場合は、コードを調べて、簡単なアルゴリズムの最適化、単純化、コードの途中でifステートメントを回避するための関数の分割などがあるかどうかを確認します。コードのプロファイルを作成し、場所を確認します。それはその時間を費やしています。
改善の各ステップの後[変更、設定などを測定し、追跡します。通常、「この変更により、4%速く実行されます」、「これにより、2%遅く実行されます」というデータを含むスプレッドシートがあります。
他のすべてのオプションを使い果たしたら、インラインアセンブラについて考え始めることができます。そして時々、あなたが「正しいことをする」ならば、大きな改善があるかもしれません。それ以外の場合は、得られるものはほとんどありません。
最近、を使用していくつかのメモリベンチマークを作成しgcc
ました。私がvolatile
(メモリ書き込みを実際に発生させるために)使用したとき、コンパイラはかなりごみのコードを生成したので、インラインアセンブラで対応するコードを書いたとき、それは3〜4倍高速でした。ただし、メモリ書き込み自体の後のステップで実際にメモリに書き込まれたものを使用するようにコードを再配置し、を削除するvolatile
と、コンパイラは私のSSE2コードと同じくらい優れていました。
複雑なSSEコードの場合、コンパイラーに少し欠けている場合もあると思いますが、かなり賢い場合もあります。単純なループを完全なSSE2コードに最適化することは確かです。
私が見つけた最大の利点は、コンパイラが実際に何をしたいのかを単純に理解していない場合です[または、必要な操作に適したコードを生成できない場合]。非一時的な移動はこの一例です-とにかくキャッシュで役に立たないことがわかっているので、キャッシュに何かを保存したくないでしょう。