Clang vs GCC-どちらがより良いバイナリを生成しますか?[閉まっている]


238

私は現在GCCを使用していますが、最近Clangを発見し、切り替えについて考えています。ただし、決定的な要素が1つあります- gcc -O3生成されるバイナリの品質(速度、メモリフットプリント、信頼性)。

ClangはGCCよりも優れたコンパイル速度と低いコンパイル時のメモリフットプリントを誇りますが、結果として得られるコンパイル済みソフトウェアのベンチマーク/比較に本当に興味があります。


5
それでも貴重な質問と回答のように思われ、多くの人が興味を示しています。
YasserAsmi 2016年

9
@YasserAsmi:そして、2つのメトリック(メモリフットプリントと実行速度)は、恣意的ではなく、「意見」の対象にもなりません。しかし、Physics.SEの病気がここに蔓延しているようで、人々はここでも質問文の詳細を読まずに投票を始めました。
SF。

12
質問はベンチマークと比較を求め、答えは両方を与えます...なぜこの意見は事実の比較ではなくですか?
oemb1905 2016

2
この質問が閉じられた理由はわかりません。それが意見に基づくものであれ、事実に基づくものであれ、私たちは答えを知りたいので、それをクローズドとしてマークすると、否定的な色合いが生じます。
ティモシーマコブ

2
@TomZych:これらの要因を知りたい場合は、別の質問をしてください。これは非常に具体的で明確です-実行速度とメモリフットプリントを求めます。あなたは他の要素に興味を持っているかもしれませんが、それはこの質問が無効であるという意味ではなく、単にあなたの個人的な興味を満たしていません。それはあなたがJavaプログラマーであり、Javaについて話していないので、すべてのC#の質問を閉じたいようです。
SF。

回答:


239

GCC 4.7.2とClang 3.2 for C ++を使った私の狭い発見ではありますが、いくつか最新の情報があります。

更新:GCC 4.8.1 v clang 3.3の比較を以下に追加。

更新:GCC 4.8.2 v clang 3.4の比較がそれに追加されました。

Linux用にGCCとClangの両方で構築されたOSSツールと、MicrosoftのWindows用コンパイラーを維持しています。ツールcoanは、C / C ++ソースファイルとそのコードラインのプリプロセッサーおよびアナライザーです。再帰降下解析とファイル処理に関する計算プロファイルを専攻します。開発ブランチ(これらの結果が関係する)は、現在約11KのLOCを約90ファイルで構成しています。現在、ポリモーフィズムとテンプレートが豊富なC ++でコード化されていますが、ハッキングされたCでのそれほど遠くない過去により、多くのパッチで取り残されています。Moveセマンティクスは明示的に利用されていません。シングルスレッドです。私はそれを最適化するために真剣な努力を傾けていませんが、「アーキテクチャ」は主にToDoのままです。

優れたコンパイル速度と診断にもかかわらず、C ++ 11標準のサポートはcoanが行使する点で現代のGCCバージョンよりも遅れていたため、私は3.2より前のClangを実験的なコンパイラとしてのみ使用しました。3.2では、このギャップは解消されました。

現在のコア開発プロセス用の私のLinuxテストハーネスは、1ファイルパーサーのテストケース、数千のファイルを消費するストレステスト、<1Kファイルを消費するシナリオテストの混合で約70Kのソースファイルを処理します。テスト結果を報告するだけでなく、ハーネスは消費されたファイルの合計とCoanで消費された実行時間を累積して表示します(各CoanコマンドラインをLinux timeコマンドに渡し、報告された数値をキャプチャして合計します)。測定可能な時間を0とするテストの数はすべて合計で0になるという事実により、タイミングはお世辞になりますが、そのようなテストの寄与は無視できます。タイミング統計は、make checkこのように最後に表示されます:

coan_test_timer: info: coan processed 70844 input_files.
coan_test_timer: info: run time in coan: 16.4 secs.
coan_test_timer: info: Average processing time per input file: 0.000231 secs.

テストハーネスのパフォーマンスをGCC 4.7.2とClang 3.2の間で比較しましたが、コンパイラ以外はすべて同じです。Clang 3.2以降、GCCがコンパイルするコード領域とClangの代替との間でプリプロセッサを区別する必要がなくなりました。それぞれのケースで同じC ++ライブラリ(GCC)をビルドし、すべての比較を同じターミナルセッションで連続して実行しました。

私のリリースビルドのデフォルトの最適化レベルは-O2です。また、-O3でビルドのテストに成功しました。各構成を3回連続してテストし、3つの結果を平均して、次の結果を得ました。データセルの数値は、〜70Kの各入力ファイルを処理するためにCoan実行可能ファイルによって消費される平均マイクロ秒数です(出力、読み取り、解析、書き込み)。

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 231 | 237 |0.97 |
----------|-----|-----|-----|
Clang-3.2 | 234 | 186 |1.25 |
----------|-----|-----|------
GCC/Clang |0.99 | 1.27|

特定のアプリケーションには、コンパイラーの長所または短所に対して不当に作用する特性がある可能性が非常に高いです。厳密なベンチマークは、さまざまなアプリケーションを採用しています。そのことを念頭に置いて、これらのデータの注目すべき機能は次のとおりです。

  1. -O3最適化はGCCにわずかに有害でした
  2. -O3最適化はClangにとって非常に有益でした
  3. -O2最適化では、GCCはウィスカだけでClangよりも高速でした
  4. -O3最適化では、ClangはGCCよりも大幅に高速でした。

2つのコンパイラのさらに興味深い比較は、これらの調査結果の直後に偶然に浮かび上がりました。Coanは、スマートポインターを自由に使用しており、その1つはファイル処理で頻繁に使用されます。この特定のスマートポインター型は、以前のリリースでコンパイラーを区別するためにtypedefされていましstd::unique_ptr<X>た。構成されたコンパイラーがその使用に対する十分に成熟したサポートを持っている場合はそうstd::shared_ptr<X>です。それ以外の場合はです。std::unique_ptrこれらのポインターが実際に転送されたため、へのバイアスは愚かでしたが、C ++ 11バリアントが私にとって新規であった時点std::unique_ptrで置き換えるためのフィッターオプションのように見え std::auto_ptrました。

Clang 3.2がこれと同様の差別化を継続的に必要std::shared_ptr<X>としていることを評価する実験的ビルドの過程で、私がビルドするつもりだったときにうっかり ビルドstd::unique_ptr<X>してしまい、デフォルトの-O2最適化で結果として得られる実行可能ファイルが最速であることに驚きました見て、時々184ミリ秒を達成しました。入力ファイルごと。ソースコードにこの1つの変更を加えると、対応する結果は次のようになります。

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 234 | 234 |1.00 |
----------|-----|-----|-----|
Clang-3.2 | 188 | 187 |1.00 |
----------|-----|-----|------
GCC/Clang |1.24 |1.25 |

ここでの注意点は次のとおりです。

  1. どちらのコンパイラーも、-O3最適化によるメリットはまったくありません。
  2. Clangは、最適化の各レベルでGCCと同じくらい重要です。
  3. GCCのパフォーマンスは、スマートポインタータイプの変更によってわずかに影響を受けるだけです。
  4. Clangの-O2パフォーマンスは、スマートポインタータイプの変更によって重要な影響を受けます。

スマートポインタータイプの変更の前後で、Clangは-O3最適化でかなり高速なcoan実行可能ファイルを構築でき、-O2と-O3でそのポインタータイプが最適な場合に同等に高速な実行可能ファイルを構築できますstd::shared_ptr<X>--仕事で。

私がコメントする能力がない明らかな質問 は、GCCが無関心であるにもかかわらず、頻繁に使用されるスマートポインタータイプが一意から共有に変更されたときに、Clangがアプリケーションで25%の-O2高速化を見つけることができる理由です。同じ変化に。また、Clangの-O2最適化には、スマートポインターの選択の知恵に対する非常に大きな感度があるという発見を応援するべきか、それとも後押しすべきかについてもわかりません。

更新:GCC 4.8.1 v clang 3.3

対応する結果は次のとおりです。

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.1 | 442 | 443 |1.00 |
----------|-----|-----|-----|
Clang-3.3 | 374 | 370 |1.01 |
----------|-----|-----|------
GCC/Clang |1.18 |1.20 |

現在、4つの実行可能ファイルすべてが1つのファイルを処理するために以前よりもはるかに長い平均時間を要しているという事実は、最新のコンパイラのパフォーマンスを反映していませ。それは、テストアプリケーションの後の開発ブランチが、その間に多くの高度な解析を採用し、その代償を払って高速化したという事実によるものです。比率のみが重要です。

ここで注目すべき点は、逮捕されたほど目新しいものではありません。

  • GCCは-O3最適化に無関心
  • clangは-O3最適化からわずかに利益を得ます
  • clangは、最適化の各レベルで同様に重要なマージンでGCCを上回っています。

これらの結果をGCC 4.7.2およびclang 3.2の結果と比較すると、GCCが各最適化レベルでclangのリードの約4分の1を折り返していることが際立っています。しかし、テストアプリケーションはその間かなり開発されてきたので、GCCのコード生成の追いつきにこれを自信を持って帰することはできません。(今回は、タイミングが取得されたアプリケーションのスナップショットを書き留めて、それを再び使用できるようにしました。)

更新:GCC 4.8.2 v clang 3.4

私はGCC 4.8.1 v Clang 3.3の更新を完了しましたが、今後の更新では同じCoanスナップショットを使用することを表明しています。しかし、代わりに、そのスナップショット(リビジョン301)、テストスイートに合格した最新の開発スナップショット(リビジョン619)でテストすることにしました。これにより、結果が少し経度になり、別の動機がありました。

私の最初の投稿では、速度を上げるためにcoanを最適化するために全力を尽くしていないことに気付きました。これは、revの時点でもまだ当てはまります。301.しかし、タイミングテスト装置をコアテストハーネスに組み込んだ後、テストスイートを実行するたびに、最新の変更によるパフォーマンスへの影響に直面しました。意外と大きいことが多いことや、機能性の向上にメリットがあると感じるよりも、トレンドが急激にネガティブであることがわかりました。

回転によって。308テストスイートの入力ファイルごとの平均処理時間は、ここに最初に投稿してから2倍以上になります。その時点で、パフォーマンスを気にしないという10年間の方針をUターンしました。頻繁に行われる改訂では、619までのパフォーマンスが常に考慮に入れられ、それらの多くは純粋に基本的な高速回線で純粋に主要な負荷ベアラーを書き換えることになりました(ただし、非標準のコンパイラー機能を使用せずに)。このUターンに対する各コンパイラの反応を見るのは興味深いでしょう。

以下は、最近の2つのコンパイラーのrev.301ビルドでおなじみのタイミングマトリックスです。

coan-rev.301の結果

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 428 | 428 |1.00 |
----------|-----|-----|-----|
Clang-3.4 | 390 | 365 |1.07 |
----------|-----|-----|------
GCC/Clang | 1.1 | 1.17|

ここでの話は、GCC-4.8.1とClang-3.3からわずかに変更されています。GCCの表示はささいなことです。Clang'sはささいなことです。ノイズはこれをよく説明します。クランはまだで先に出てくる-O2-O3、ほとんどのアプリケーションでは問題ではないだろうが、かなりの数には関係でしょう余白。

そして、これがrevのマトリックスです。619。

coan-rev.619の結果

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 210 | 208 |1.01 |
----------|-----|-----|-----|
Clang-3.4 | 252 | 250 |1.01 |
----------|-----|-----|------
GCC/Clang |0.83 | 0.83|

301と619の数字を並べると、いくつかの点がわかります。

  • 私はより速いコードを書くことを目指していました、そして両方のコンパイラーは私の努力をはっきりと証明します。だが:

  • GCCはClangよりもはるかに寛大にそれらの努力を払い戻します。で-O2 最適化クランの619ビルドが46%速くその301のビルドより:で-O3クランの改善31%です。良いですが、各最適化レベルで、GCCの619ビルドは、301の2倍以上高速です。

  • GCCはClangの以前の優位性を覆すだけではありません。そして、各最適化レベルで、GCCはClangを17%上回る。

  • 301ビルドでのClangの機能は、-O3最適化からGCCより多くのレバレッジを得ることができますが、619ビルドではなくなりました。どちらのコンパイラもから意味のある利益を得ません-O3

この運命の逆転に十分驚いて、誤ってclang 3.4自体を緩やかにビルドしたのではないかと疑いました(ソースからビルドしたため)。それで、ディストリビューションのストックClang 3.3で619テストを再実行しました。結果は3.4とほぼ同じでした。

したがって、Uターンに対する反応に関しては、ここでの数値については、Clangは、C ++コードの助けを借りていなかったときの速度でGCCよりもはるかに優れています。私が助けることに心を向けたとき、GCCはClangよりもはるかに優れた仕事をしました。

私はその観察を原則にまで高めませんが、「どのコンパイラーがより優れたバイナリーを生成するのか」という教訓を持ちます。答えが相対的であるべきテストスイートを指定したとしても、バイナリのタイミングを計るだけの明確な問題ではありません。

あなたのより良いバイナリは最速のバイナリですか、それとも安価に作成されたコードを最もよく補償するものですか?または 、速度よりも保守性と再利用を優先する、費用のかかる細工されたコードを最もよく補償しますか?それは、バイナリを生成する動機の性質と相対的な重み、およびそれを行う際の制約に依存します。

いずれにせよ、「最良の」バイナリの構築に深く関心がある場合は、コンパイラの連続した反復がコードの連続した反復に対する「最良の」というアイデアをどのように実現するかを確認し続けることをお勧めします。


9
なぜclangの方が速いのですか?たとえば、IntelコンパイラはIntelチップの専門分野を使用していました。利点を得るためにclangは何を使用していますか?gccが同じパフォーマンスになるようにコードを書き換えることはできますか?
kirill_igum 2013年

27
@krill_igum GCCとclangは、同じ仕事をするために異なるプログラマグループによって書かれた異なる(非常に複雑な)プログラムです:ソースコードをオブジェクトコードに変換します。いずれかの時点で選択されたテストで、一方が他方よりもかなりうまくその仕事をすることはほぼ避けられません。勝者が「アドバンテージを獲得」するために「使用」している特別な「もの」は必要ありません。両方のプログラムはオープンソースであるため、お互いに秘密はありません。
Mike Kinghan 2013年

3
を使用kcachegrindして、生成された実行可能ファイルのパフォーマンスが異なる関数を特定できます。

4
-1:これは答えというより小説(またはブログ投稿)です。
John Saunders

60
@JohnSaunders:ある人にとって何が詳細で詳細な答えであるか、別の人にとっては彼らの注意に値しない小説です。これら2人の違いを教えてください。
SF。

48

Phoronixはこれについていくつかのベンチマークを行いましたが、これは数か月前のClang / LLVMのスナップショットバージョンに関するものです。その結果、物事は多かれ少なかれプッシュでした。GCCもClangも、すべてのケースで明らかに優れています。

最新のClangを使用するため、関連性は少し低くなります。また、GCC 4.6はCore 2とi7に対していくつかの主要な最適化を行う予定です。

元の開発者にとってはClangのコンパイル速度が速い方がいいと思います。その後、コードを世に送り出すと、Linuxディストリビューション/ BSD / etcなどになります。エンドユーザーはGCCを使用してより高速なバイナリを作成します。


2
今日だけClangコンパイル速度でいくつかのベンチマークを実行しましたが、純粋なCには非常に残念です。270KLOC clangを使用して35個のCファイルをコンパイルすると、25%速くなりました。Linuxでのtinyccの速度が速いことを確認すると、新しく作成されたコンパイラにとっては悪い結果です。最適化-O2 / -O3を使用すると改善されますが、リリースビルドに使用されるため、この場合コンパイラのパフォーマンスは重要ではありません。
Lothar

7
@mcandreたぶんNietzche-jouはClangでコンパイルされましたが、GCCでコンパイルされました。
Mateen Ulhaq、2011

18

Clangがコードをより速くコンパイルするという事実は、結果のバイナリの速度ほど重要ではない可能性があります。ただし、ここに一連のベンチマークがあります


12
実際にはそうです。開発中、コンパイル時間(およびコンパイルによるリソースの消費)は、バイナリパフォーマンスよりもはるかにボトルネックになります。結局のところ、この段階ではデバッグモードでコンパイルします。テストして出荷する段階になって初めて、リリースモードに切り替えて、できるだけ高速なバイナリを取得しようとします。
Matthieu M.

3
@ Matthieu M:彼が潜在的な懸念を引き起こしているかのように、私はその答えが「かもしれない」と言ったことを誓います。多分、それはOPに関連していたので、言及する価値があったと思います。
JMベッカー

同意しますが、すべての良い点はここにあります。2番目または3番目のRAID 0ドライブ、SSD、またはより高速なRAMを投入し、最高の.exeパフォーマンスを実現したいのですが、これらの方法でパリティまたは終了に到達できます。また、複数のコンパイラで開発すると役立つ場合もあります。これにより、移植性のない機能を認識し、他の方法では検出されないエラーをキャッチしたり、より優れたコンパイラーが警告/エラーを生成したりしてコードをデバッグしようとすると何日も無駄に時間を費やすことになります。

私が書いたいくつかのタイトなパフォーマンスクリティカル整数コードを比較してみましたが、GCCは-O2と-O3の両方を使用して、はるかに高速に実行されました(22S clang-llvm 25S)。コンパイラスイッチ(gccまたはclang)の使用は、ほとんどの非標準機能と静的警告に対応していると考えてください。あなた自身の大きなプロジェクトでは、他のpplのコードをバッチコンパイルするのではなく、コンパイル時間がリンク時間を支配している場合、ビルドシステムで何か問題があります。頻繁にクリーンアップを行う場合に役立つccache.samba.orgのようなツールがあります。コンパイラの変更に関するもう1つの問題は、破棄されるテスト/検証への常にの投資です。
Rob11311 2014

code.google.com/p/distccは、データ構造の変更や検証/検証のためにライブラリ全体を再コンパイルする必要がある場合、一括コンパイル時間を短縮できる別のプロジェクトです
Rob11311

11

結果のバイナリの速度に関して、GCC 4.8とclang 3.3の全体的な違いはほとんどありません。ほとんどの場合、両方のコンパイラによって生成されたコードは同様に動作します。これら2つのコンパイラーはどちらも、もう一方のコンパイラーを支配していません。

GCCとclangの間に大きなパフォーマンスギャップがあることを示すベンチマークは偶然の一致です。

プログラムのパフォーマンスは、コンパイラーの選択によって影響を受けます。開発者または開発者のグループがGCCのみを使用している場合、プログラムはGCCを使用するとclangを使用した場合よりもわずかに速く実行され、逆の場合も同様です。

開発者の観点からは、GCC 4.8+とclang 3.3の顕著な違いは、GCCに-Ogコマンドラインオプションがあることです。このオプションは、デバッグを妨げない最適化を有効にするため、たとえば、常に正確なスタックトレースを取得できます。clangにこのオプションがないと、一部の開発者にとって最適化コンパイラーとしてclangを使用することが難しくなります。


最近、(3.3と4.8)コンパイル時間に大きな違いは見られません。(コンパイル時間が10秒から30秒の「マイ」プログラムでは)。
alfC

9

これを決定する唯一の方法は、それを試すことです。FWIW AppleのLLVM gcc 4.2を使用すると、通常のgcc 4.2(SSEがかなり多いx86-64コードの場合)に比べていくつかの優れた改善が見られますが、YMMVはさまざまなコードベースに対応しています。x86 / x86-64で作業していて、最後の数パーセントを本当に気にしているとしたら、IntelのICCも試す必要があります。これは、gccに勝ることが多いためです。intel.comから30日間の評価ライセンスを取得できます。そしてそれを試してみてください。


8

私がgcc 5.2.1とclang 3.6.2で指摘した特異な違いは、次のようなクリティカルループがある場合です。

for (;;) {
    if (!visited) {
        ....
    }
    node++;
    if (!*node) break;
  }

次に、gccは、-O3または-O2でコンパイルするときに、ループを投機的に8回アンロールします。Clangはアンロールしません。試行錯誤の結果、プログラムデータを使用した特定のケースでは、アンロールの適切な量は5であるため、gccがオーバーシュートし、clangがアンダーシュートしていることがわかりました。ただし、オーバーショットはパフォーマンスに悪影響を及ぼしたため、gccのパフォーマンスはここで大幅に低下しました。

私は持っていないないアイデアを展開差が一般的な傾向や私のシナリオに特異的であっただけで何かあれば。

しばらく前に、Cでのパフォーマンスの最適化についてもっと学ぶためにいくつかのガベージコレクターを書いた。特にガベージコレクションは、ほとんどの場合、メモリを追跡してコピーするポインタに関するものです。

結果は(秒単位の数値)です。

+---------------------+-----+-----+
|Type                 |GCC  |Clang|
+---------------------+-----+-----+
|Copying GC           |22.46|22.55|
|Copying GC, optimized|22.01|20.22|
|Mark & Sweep         | 8.72| 8.38|
|Ref Counting/Cycles  |15.14|14.49|
|Ref Counting/Plain   | 9.94| 9.32|
+---------------------+-----+-----+

これはすべて純粋なCコードであり、C ++コードをコンパイルする際のどちらのコンパイラのパフォーマンスについても主張しません。

Ubuntu 15.10、x86.64、およびAMD Phenom(tm)II X6 1090Tプロセッサー。


4

基本的には、答えは次のとおりです。さまざまな種類のアプリケーションに焦点を当てた多くのベンチマークがあります。

私のアプリのベンチマークは、gcc> icc> clangです。

まれなIOがありますが、多くのCPUフロートおよびデータ構造操作。

コンパイルフラグは-Wall -g -DNDEBUG -O3です。

https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.