これは、GCC4.7.2およびC++用のClang3.2を使用した私の調査結果ではありますが、最新のものです。
更新:GCC 4.8.1 vclang3.3の比較を以下に追加。
更新:GCC 4.8.2 vclang3.4の比較がそれに追加されます。
私は、GCCとClangの両方を備えたLinux用に構築されたOSSツールと、Windows用のMicrosoftのコンパイラを維持しています。ツールcoanは、C / C++ソースファイルとそのコードラインのプリプロセッサおよびアナライザーです。再帰下降構文解析とファイル処理を専攻する計算プロファイルです。開発ブランチ(これらの結果が関係する)は、現在、約90個のファイルに約11KLOCで構成されています。現在、ポリモーフィズムとテンプレートが豊富なC ++でコーディングされていますが、ハッキングされたCでのそれほど遠くない過去によって、多くのパッチでまだ悩まされています。移動セマンティクスは明示的に利用されていません。シングルスレッドです。私はそれを最適化するために真剣な努力をしていませんが、「アーキテクチャ」は非常に大部分がToDoのままです。
私は3.2より前のClangを実験的なコンパイラとしてのみ使用しました。これは、その優れたコンパイル速度と診断にもかかわらず、C++11標準サポートがcoanによって行使される点で現代のGCCバージョンに遅れをとっていたためです。3.2では、このギャップは埋められました。
現在のcoan開発用の私のLinuxテストハーネスは、1ファイルパーサーテストケース、数千のファイルを消費するストレステスト、および1K未満のファイルを消費するシナリオテストの混合で約70Kのソースファイルを処理します。
ハーネスは、テスト結果を報告するだけでなく、消費されたファイルの合計とcoanで消費された実行時間を累積して表示します(各coanコマンドラインをLinuxtime
コマンドに渡し、報告された数をキャプチャして合計します)。測定可能な時間が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.
テストハーネスのパフォーマンスをGCC4.7.2とClang3.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|
特定のアプリケーションには、コンパイラの長所または短所に不当に作用する特性がある可能性が非常に高くなります。厳密なベンチマークでは、さまざまなアプリケーションが採用されています。そのことを十分に念頭に置いて、これらのデータの注目すべき機能は次のとおりです。
- -O3の最適化はGCCにわずかに有害でした
- -O3の最適化はClangにとって非常に有益でした
- -O2最適化では、GCCはウィスカーだけでClangよりも高速でした
- -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
これと同様の差別化に対するClang3.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 |
ここでの注意点は次のとおりです。
- 現在、どちらのコンパイラも-O3最適化の恩恵を受けていません。
- Clangは、最適化の各レベルで同様に重要なことにGCCを上回っています。
- GCCのパフォーマンスは、スマートポインターのタイプの変更によってわずかに影響を受けるだけです。
- Clangの-O2パフォーマンスは、スマートポインターのタイプの変更によって重要な影響を受けます。
スマートポインタータイプの変更の前後で、Clangは-O3最適化で大幅に高速な実行可能ファイルを構築でき、そのポインタータイプが最適な場合は-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を上回っています。
これらの結果をGCC4.7.2およびclang3.2の結果と比較すると、GCCが各最適化レベルでclangのリードの約4分の1を取り戻していることがわかります。しかし、その間にテストアプリケーションが大幅に開発されたため、これをGCCのコード生成のキャッチアップに自信を持って帰することはできません。(今回は、タイミングを取得したアプリケーションのスナップショットをメモして、再度使用できるようにしました。)
更新:GCC 4.8.2 v clang 3.4
GCC 4.8.1 v Clang 3.3のアップデートを終了し、今後のアップデートでは同じcoansnaphotに固執すると述べました。しかし、代わりに、そのスナップショット(rev。301)と、テストスイート(rev。619)に合格した最新の開発スナップショットでテストすることにしました。これは結果に少し経度を与えます、そして私は別の動機を持っていました:
私の最初の投稿は、私が速度のためにcoanを最適化することに何の努力も捧げていなかったことを指摘しました。これは、revの時点でも当てはまりました。301.しかし、タイミング装置をcoanテストハーネスに組み込んだ後、テストスイートを実行するたびに、最新の変更によるパフォーマンスへの影響に直面しました。それはしばしば驚くほど大きく、機能性の向上によってメリットがあると感じたよりも、傾向が急激にネガティブであることがわかりました。
回転によって。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はささいなことです。ノイズがこれを十分に説明している可能性があります。Clangはまだ先を行って-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
、Clangの619ビルドは301ビルドよりも46%高速です-O3
。Clangの改善では31%です。良いですが、各最適化レベルで、GCCの619ビルドは301の2倍以上高速です。
GCCは、Clangの以前の優位性を覆す以上のものです。そして、各最適化レベルで、GCCはClangを17%上回っています。
最適化からGCCよりも多くのレバレッジを取得する301ビルドでのClangの機能は-O3
、619ビルドではなくなりました。どちらのコンパイラも。から意味のある利益を得ることができません-O3
。
この運命の逆転に私は十分に驚いたので、誤ってclang 3.4自体のビルドが遅くなったのではないかと思いました(ソースからビルドしたため)。そこで、ディストリビューションのストックであるClang3.3を使用して619テストを再実行しました。結果は3.4の場合と実質的に同じでした。
したがって、Uターンへの反応に関して:ここでの数値では、Clangは、助けを与えていないときに、C++コードからの絞り込み速度でGCCよりもはるかに優れています。私が支援することに心を向けたとき、GCCはClangよりもはるかに優れた仕事をしました。
私はその観察を原則に昇格させませんが、「どのコンパイラがより良いバイナリを生成するか」という教訓を取ります。答えが相対的なテストスイートを指定したとしても、バイナリのタイミングを調整するだけの明確な問題ではないという質問です。
あなたのより良いバイナリは最速のバイナリですか、それとも安価に作成されたコードを最もよく補償するものですか?
または、保守性と速度よりも再利用を優先する、高価に作成されたコードを最もよく補償しますか?それは、バイナリを生成する動機の性質と相対的な重み、およびそれを行う際の制約に依存します。
いずれにせよ、「最高の」バイナリの構築に深く関心がある場合は、コンパイラの連続した反復が、コードの連続した反復で「最良」のアイデアをどのように実現するかを確認し続ける必要があります。