私は現在GCCを使用していますが、最近Clangを発見し、切り替えについて考えています。ただし、決定的な要素が1つあります- gcc -O3
生成されるバイナリの品質(速度、メモリフットプリント、信頼性)。
ClangはGCCよりも優れたコンパイル速度と低いコンパイル時のメモリフットプリントを誇りますが、結果として得られるコンパイル済みソフトウェアのベンチマーク/比較に本当に興味があります。
私は現在GCCを使用していますが、最近Clangを発見し、切り替えについて考えています。ただし、決定的な要素が1つあります- gcc -O3
生成されるバイナリの品質(速度、メモリフットプリント、信頼性)。
ClangはGCCよりも優れたコンパイル速度と低いコンパイル時のメモリフットプリントを誇りますが、結果として得られるコンパイル済みソフトウェアのベンチマーク/比較に本当に興味があります。
回答:
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|
特定のアプリケーションには、コンパイラーの長所または短所に対して不当に作用する特性がある可能性が非常に高いです。厳密なベンチマークは、さまざまなアプリケーションを採用しています。そのことを念頭に置いて、これらのデータの注目すべき機能は次のとおりです。
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 |
ここでの注意点は次のとおりです。
スマートポインタータイプの変更の前後で、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 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よりもはるかに優れた仕事をしました。
私はその観察を原則にまで高めませんが、「どのコンパイラーがより優れたバイナリーを生成するのか」という教訓を持ちます。答えが相対的であるべきテストスイートを指定したとしても、バイナリのタイミングを計るだけの明確な問題ではありません。
あなたのより良いバイナリは最速のバイナリですか、それとも安価に作成されたコードを最もよく補償するものですか?または 、速度よりも保守性と再利用を優先する、費用のかかる細工されたコードを最もよく補償しますか?それは、バイナリを生成する動機の性質と相対的な重み、およびそれを行う際の制約に依存します。
いずれにせよ、「最良の」バイナリの構築に深く関心がある場合は、コンパイラの連続した反復がコードの連続した反復に対する「最良の」というアイデアをどのように実現するかを確認し続けることをお勧めします。
Phoronixはこれについていくつかのベンチマークを行いましたが、これは数か月前のClang / LLVMのスナップショットバージョンに関するものです。その結果、物事は多かれ少なかれプッシュでした。GCCもClangも、すべてのケースで明らかに優れています。
最新のClangを使用するため、関連性は少し低くなります。また、GCC 4.6はCore 2とi7に対していくつかの主要な最適化を行う予定です。
元の開発者にとってはClangのコンパイル速度が速い方がいいと思います。その後、コードを世に送り出すと、Linuxディストリビューション/ BSD / etcなどになります。エンドユーザーはGCCを使用してより高速なバイナリを作成します。
Clangがコードをより速くコンパイルするという事実は、結果のバイナリの速度ほど重要ではない可能性があります。ただし、ここに一連のベンチマークがあります。
結果のバイナリの速度に関して、GCC 4.8とclang 3.3の全体的な違いはほとんどありません。ほとんどの場合、両方のコンパイラによって生成されたコードは同様に動作します。これら2つのコンパイラーはどちらも、もう一方のコンパイラーを支配していません。
GCCとclangの間に大きなパフォーマンスギャップがあることを示すベンチマークは偶然の一致です。
プログラムのパフォーマンスは、コンパイラーの選択によって影響を受けます。開発者または開発者のグループがGCCのみを使用している場合、プログラムはGCCを使用するとclangを使用した場合よりもわずかに速く実行され、逆の場合も同様です。
開発者の観点からは、GCC 4.8+とclang 3.3の顕著な違いは、GCCに-Og
コマンドラインオプションがあることです。このオプションは、デバッグを妨げない最適化を有効にするため、たとえば、常に正確なスタックトレースを取得できます。clangにこのオプションがないと、一部の開発者にとって最適化コンパイラーとしてclangを使用することが難しくなります。
私が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プロセッサー。
基本的には、答えは次のとおりです。さまざまな種類のアプリケーションに焦点を当てた多くのベンチマークがあります。
私のアプリのベンチマークは、gcc> icc> clangです。
まれなIOがありますが、多くのCPUフロートおよびデータ構造操作。
コンパイルフラグは-Wall -g -DNDEBUG -O3です。
https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark