「可能性が高い」および「可能性が低い」マクロの使用量は多すぎますか?


12

よく知られlikelyているunlikelyマクロとマクロは、コンパイラifが通常入力されるかスキップされるかを知るのに役立ちます。これを使用すると、パフォーマンスが多少(わずかに)向上します。

私は最近それらを使い始めましたが、そのようなヒントをどのくらいの頻度で使用すべきかわかりません。現在、エラーチェックで使用します。if通常はとしてマークされunlikelyます。例えば:

mem = malloc(size);
if (unlikely(mem == NULL))
  goto exit_no_mem;

それは問題ないように見えますが、エラーチェックはif非常に頻繁に発生し、その結果、上記のマクロが使用されます。

私の質問は、すべてのエラーチェックでマクロlikelyunlikelyマクロを持っているのは多すぎるのifですか?

我々がそれに取り組んでいる間、彼らは他のどのような場所でよく使われますか?


私の現在の使用法では、リアルタイムサブシステムから抽象化するライブラリにあるため、プログラムはRTAI、QNXなどの間で移植可能になります。ただし、ほとんどの関数はかなり小さく、1つまたは2つの他の関数を直接呼び出します。多くはstatic inline機能です。

だから、まず第一に、それは私がプロファイルできるアプリケーションではありません。スタンドアロンアプリケーションではなくライブラリであるため、「ボトルネックを特定する」ことは意味がありません。

第二に、「これはありそうもないことを知っているので、コンパイラに伝えることもできます」というようなものです。私は積極的に最適化しようとしませんif


7
私にはマイクロ最適化のにおい...
ラチェットフリーク

2
アプリケーションコードの場合、プロファイリングでこのコードがホットパスで使用されていることが示された場合にのみ追加します。
CodesInChaos


@james、それはただ言いlikelyunlikely存在し、彼らが何をするか。それらをいつ、どこで使用するのが最適かを実際に示唆するものは見つかりませんでした。
シャーバズ

@Shahbaz「条件が頻繁にfalseである場合、実行は線形ではありません。プリフェッチによりL1iを汚染するだけでなく、中間に大きな未使用コードのチャンクがあります。分岐予測が間違っています。条件式は非常に非効率的です。」したがって、必要な命令がL1iキャッシュにあることを確認したいタイトなループ
James

回答:


12

あなたはそれであなたのコードを汚染しようとするほどひどいパフォーマンスが必要ですか?それはマイナーな最適化です。

  • コードはタイトループで実行されますか?
  • アプリケーションにパフォーマンスの問題がありますか?
  • アプリケーションのプロファイルを作成し、この特定のループには多くのCPU時間がかかると判断しましたか?

yes上記のすべてに答えることができない限り、このようなことを気にしないでください。

編集:編集への応答。プロファイルできない場合でも、通常はホットスポットを推定できます。誰でも呼び出されるメモリ割り当て関数は、特にライブラリ全体で機能するためにマクロを1回使用するだけでよいため、良い候補です。


1
明確にするために、私はあなたに反対票を投じなかった。しかし、あなたの答えは本当に私の質問に答えません。(un)likelyマクロはめったに使用されず、パフォーマンスが非常に重要なコードでのみ使用されると言いたいですか?頻繁に使用するのは「悪い習慣」ですか、それとも単に「不要」ですか?
シャーバズ

@Shahbazコードを読みにくくし、パフォーマンスの最適化は些細な利得から些細な損失までの範囲に及ぶ可能性があります。後者は、尤度に関する仮定が不正確であったか、またはコードの他の部分への後での変更により不正確になるように変更された場合です。必要な場合を除き、使用しないでください。
ピーター

3
@Peter:構文はあまり良くありませんが、コードを読んでいる人間に役立つ可能性のある表記またはそうでない表記は有用な情報を提供します。たとえば、を見た人はif (likely(x==2 || x==3)) doOneThing(); else switch(x) { ... }、プログラマifが値2と3にを使用したのは、Cが2つのcaseラベルを1つのハンドラに関連付けることができることをプログラマが知らなかったためではないと判断するかもしれません。
supercat

誰も私が重要だと感じていることについて言及していません。「起こりそうにない」パスの発生頻度が低いというだけでなく、そのパスが発生することを条件として、速度をまったく気にしないこともあります。たとえば、周辺機器は応答しなくなるため、リセットしてスリープする必要があります。
ベンジャミンリンドクヴィスト

2

x86 / x64向けに書いている(そして20年前のCPUを使用していない)場合、__ builtin_expect()を使用することによるパフォーマンスの向上は、あるとしてもごくわずかです。その理由は、最新のx86 / x64 CPU(ただし、Atomについては100%確実ではありません)には動的な分岐予測があるため、基本的にCPUはより頻繁に使用される分岐について「学習」します。もちろん、この情報は限られた数のブランチについてのみ保存できますが、可能なケースは2つだけです。(a)「頻繁に使用される」ブランチである場合、プログラムはその動的なブランチ予測の恩恵を受け、(b)それが「まれな」ブランチである場合、このようなまれな分岐(20 CPUサイクルの分岐予測ミスは、ブルームーンに一度発生したとしても悪くありません)。

注意:これは、現代のx86 / x64で分岐予測の重要性が低くなったことを意味するものではありません。まだ避ける必要があります。減少したx86 / x64上の__builtin_expect()の重要性のみ(IIRC、約10〜15年前)-主に動的分岐予測のためです。

NB2:x86 / x64以外のプラットフォームの場合、YMMV。


さて、コンパイラーは、cpuがどのブランチをより少ない可能性で期待するかを知っています。そして、それが実際にありそうもないものになるように手配することができます。しかし、コンパイラーはおそらく- unlikely表記なしでそのパターンを既に知っています。
デュプリケータ

@Deduplicator:動的な分岐予測では、コンパイラは、CPUがコード内のこのポイントを介した以前の実行に基づいて実行時に計算するため、どの分岐が発生する可能性が高いかを知りません。
いいえバグうさぎ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.