gcc macro string - Linuxカーネルの可能性の高い/考えにくいマクロはどのように機能し、そのメリットは何ですか?





5 Answers

これらは、分岐がどのように進むかについてのヒントをコンパイラに与えるマクロです。 利用可能な場合、マクロはGCC固有の拡張に展開されます。

GCCはこれらを使用して分岐予測を最適化します。 たとえば、次のようなものがある場合

if (unlikely(x)) {
  dosomething();
}

return x;

それから、このコードを以下のように再構成することができます:

if (!x) {
  return x;
}

dosomething();
return x;

この利点は、初めてプロセッサをブランチにするときに、かなり先にロードして実行していた可能性があるため、かなりのオーバーヘッドがあることです。 それがブランチを取ると判断したら、それを無効にして、ブランチターゲットから開始する必要があります。

最新のプロセッサーには分岐予測がありますが、これは以前分岐を通過した時点でのみ役立ち、分岐予測は依然として分岐予測キャッシュにあります。

これらのシナリオでは、コンパイラとプロセッサが使用できる他の多くの戦略があります。 分岐予測子がWikipediaでどのように機能するかについて詳しくは、 http : //en.wikipedia.org/wiki/Branch_predictor

linux gcc linux-kernel compiler-construction likely-unlikely

私はLinuxカーネルのいくつかの部分を掘り下げて、次のような呼び出しを見つけました:

if (unlikely(fd < 0))
{
    /* Do something */
}

または

if (likely(!err))
{
    /* Do something */
}

私はそれらの定義を見つけました:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

私は彼らが最適化のためのものだと知っていますが、どのように機能しますか? そして、それらを使用することによってどの程度のパフォーマンス/サイズの減少が期待できますか? 少なくとも、ボトルネックコード(ユーザスペースではもちろん)では、面倒なことに価値がある(おそらく移植性を失うかもしれない)。




コンパイラは、ハードウェアがサポートする適切な分岐ヒントを発行します。 これは、通常、命令オペコードのビット数を変えることを意味し、コードサイズは変更されません。 CPUは、予測された位置から命令をフェッチし始め、パイプラインをフラッシュし、ブランチに到達したときに間違っていると判明した場合は再始動します。 ヒントが正しい場合には、これはブランチをはるかに高速にします。正確にはハードウェアに依存する速度はどれくらいですか。 これがコードのパフォーマンスにどの程度影響を与えるかは、時間ヒントのどの部分が正しいかによって異なります。

例えば、PowerPC CPUでは、ヒントなしのブランチは16サイクルかかり、正しくヒントされたものは8、ヒントが正しくないものは24となります。最も内側のループでは、ヒントが大きな違いを生むことがあります。

移植性は実際問題ではありません。おそらく、定義はプラットフォームごとのヘッダにあります。 静的な分岐のヒントをサポートしていないプラットフォームでは、「可能性が高い」と「そう思わない」を単純に定義できます。




(一般的なコメント - その他の回答は詳細をカバーしています)

あなたがそれらを使って移植性を失うべき理由はありません。

他のプラットフォームで他のコンパイラを使用してコンパイルできるようにする、単純なnil-effectの "インライン"マクロを作成するオプションが常にあります。

他のプラットフォームであれば、最適化のメリットは得られません。




多くのLinuxリリースでは、/ usr / linux /にあるcomplier.hを見つけることができます。単純に使用するためにそれを含めることができます。 そして、別の意見では、()の可能性が高いのではなく、

if ( likely( ... ) ) {
     doSomething();
}

多くのコンパイラで最適化することができます。

そして、コードの詳細な動作を観察したい場合は、次のように簡単に行うことができます:

gcc -c test.c objdump -d test.o> obj.s

次に、obj.sを開いて、答えを見つけることができます。




これらはGCCの関数であり、与えられた式のなかで最も分岐しやすい条件について、コンパイラにヒントを与えるためのものです。 これにより、最も一般的なケースが実行する命令の数が最も少なくなるように、コンパイラは分岐命令を構築することができます。

分岐命令がどのように構築されるかは、プロセッサのアーキテクチャに依存します。




Related