ソースから C++ をビルドする:パート 1/N - コンパイル時間の短縮

これは、私の CppCon トークと進行中の ABI サーガのフォローアップであり、すぐに終わるとは思っていません。

この記事が、今後数か月にわたって執筆したいと考えているシリーズの最初の記事になることを願っています。

簡単に思い出してください。ABI はバイナリ プロトコルに似ており、型をメモリに配置する方法、関数をマングルして呼び出す方法を決定します。そのため、コンパイル時に表示されないプログラムのソースの多くの変更が明らかになります。リンク時または実行時。ABI の安定性は、一貫した環境で構築されていないライブラリをリンクまたはロードしようとする場合にのみ関連します。一貫した環境とは何かに戻ります。

WG21 プラハ会議に続いて、多くの人々が ABI 問題を解決しようとしています。最終的に、提案されているすべてのソリューションは次のように要約されます。

  • 部分的に無音の ABI ブレーク (C++11 で 03 で行われたのと同様) )
  • 新しい名前または新しい名前空間、または最終的にそれを行う他のメカニズムによる型の複製。
  • COM ライク、PIMPL ライク、または意味的に同等の洗練されたソリューションに関係なく、間接的なレベルを追加します。

これらの解決策のいずれも、C++ 標準ライブラリのコンテキストでは機能しないと思います.いつか理由を説明しようとするかもしれません.

しかし、ABI の安定性には C++ の本質に反するコストがかかるという前提で、どのような解決策が残っていても、それが困難であっても前進する必要があります。ソースからのビルドについて話しましょう。

人々がソースからビルドしない理由、またはそうすることが現実的ではないと考えている理由を理解することが重要です。その理由は次のとおりだと思います:

  • ソースからのコンパイルには時間がかかります
  • 大きなバイナリはディスクとメモリ スペースを占有します
  • ビルド システムが複雑なため、ソースからのコンパイルは困難です。
  • 法的な理由により、ソースにアクセスせずに商用ソフトウェアを使用する
  • ソースが失われたライブラリの使用
  • システムが提供するコンパイル済みライブラリの使用
  • ある種のプラグイン システムの使用

(これらのカテゴリのいずれにも当てはまらないものを忘れた場合はお知らせください)

今後数週間のうちに、これらの問題のそれぞれについて一連の記事をリリースしたいと考えています。今日は、C++ のビルド時間を短縮できるさまざまなソリューションの紹介に焦点を当てます .

C++ のビルドを高速化

C++ は、間違いなくコンパイルが少し遅いです。十分に遅いため、人々はビルド済みのバイナリをダウンロードして、そのコンパイルのコストを支払う必要はありません。

C++ のビルドを高速化するソリューションがいくつかあります。

より良いハードウェアを使用する

このパートは主に雇用主を対象としています。特に、愛好家や学生などの場合は、手頃な価格のハードウェアが必要だとは思わないでください。ハードウェアは問題ありません .

C++ のコンパイルは遅いです。意図的に。アイデアは、コンパイル時に多くのことを行い、実行時に少なくすることです。誰かが抽象化のコストを支払わなければならず、C++ はユーザーではなく開発者にそのコストを支払わせることを選択します。プログラムは通常、コンパイルされるよりもはるかに多くのマシンで実行されるため、これは賢明なことです。

コンパイラが十分に最適化されていないという意味ではありませんが、C++ コンパイラの速度には限界があります。

幸いなことに、コンパイラは複数のスレッドを使用していないように見えますが、多数の C++ ソース ファイルを一度にコンパイルするのは簡単です。 C++ コンパイルは、ハードウェアで許可されている場合、並列ジョブの数にほぼ比例して拡張されます。幸いなことに、多くのコアを搭載した CPU の購入と所有は安価になっています。12、16 コアでは、24、32 をコンパイルできます。同時に翻訳単位。 LLVM ツールチェーン全体を 10 分未満で簡単にコンパイルできるようにします。もちろん、これらの CPU は安くはありませんが、数年前よりも確実に大幅に安くなっており、この傾向は続く可能性があります。

高価な CPU が必要だとか、C++ を使用するには高価な CPU が必要だとは誰にも言いたくありませんが、これはビジネス上の決定事項だと思います。ハードウェアに投資することで、確実に生産性が向上しました。VFX または CAD 業界の人々は、仕事で生産性を高めるには高価なハードウェアが必要であることを理解しています (これは、非専門家向けの控えめなハードウェアのネストを排除するものではありません)。

ハードウェアとは?

考慮すべき点がいくつかあります:

  • AMD CPU は現在 Intel の CPU よりも安価ですが、13 などのツールでは動作しない可能性があります そして 20 .私は Ryzen 3xxx を使用しましたが、私にはぴったりです。
  • おそらく、論理コアごとに 1 ~ 2 GB が必要です。 16 コアの CPU を使用する場合は、48 ~ 64 GB の RAM が必要になる場合があります
  • 高速ドライブは、一部の操作、特にプロファイリングとデバッグを高速化しますが、コンパイルにはあま​​り影響を与えないようです
  • C++ を使用すると、コンパイルとは関係なくリソースが使用されます。デバッグ、プロファイリング、コードのインデックス作成 (IDE を使用) は、CPU、メモリ、ドライブに同様に負担をかけます。

CI はどうですか?

Contiguous Integration プラットフォームを管理する場合、コミットとマージの速度に応じて、同じハードウェアの推奨事項が適用されます。

残念なことに、ほとんどのクラウド サービスは適度なハードウェア (通常は数コア) を提供するため、大規模なフレームワークのコンパイルは、不可能ではないにしても非常に遅くなります. これらのクラウド CI がオープンソース コミュニティに無料で提供する多大なメリットを考えると、文句を言うのは非常に困難です.これらのオファーは、多くのオープンソース C++ プロジェクトにはあまり適していません。より多くのコアが必要です!特定の期間のビルド数を制限しながらより高速なビルドを提供することは、ユーザーと CI プロバイダーの両方にとって理にかなっているのだろうか.

キャッシング

LLVM、Qt、またはブーストを数分で再コンパイルできるからといって、ビルドを開始するたびに再コンパイルできるわけではありません。 ソースから。

これには非常に具体的な意味があります。キャッシング メカニズムの存在は、最終的なプログラムによって監視可能であってはなりません。C++ プログラムのコンパイルは、コンパイラ、コンパイラ フラグ、含まれるヘッダー、およびリンクされるライブラリによって影響を受ける可能性があります。多くの場合、ヘッダーはシステム全体にインストールされます。できればシステム ライブラリ ヘッダーのみを使用してください。これについては今後の記事で説明します。

そのため、プリコンパイル済みライブラリ (静的または動的) の使用またはプリコンパイル済みモジュールの使用はキャッシングを構成するものではなく、診断が不要なプログラムの形式が正しくない正当な理由となります。モジュールを再配布しない> .

多くのものをキャッシュできます:

変更の追跡

ビルド システムの仕事は、ファイル、コンパイラ オプション、およびその他の依存関係が変更されるたびに、ビルドを実行するために必要な最小限かつ十分な量の作業を追跡することです。

翻訳単位のキャッシュ

34 のようなツール と 43 不要な場合にオブジェクト ファイルを再構築しないようにします。優れたビルド システムは、多くの場合、このようなツールの必要性を軽減するはずですが、実際には非常に有用であることが証明されています。

モジュール

モジュールなしでエコシステムの状態を有意義に改善できるとは思いません.コンパイル速度に関する限り、モジュールはプリコンパイル済みヘッダーとして機能することができます(モジュールにはコンパイル速度以外の利点があります).モジュールインターフェイスを解析するだけで済みます. once.And テンプレート 使用 これにより、コンパイルが大幅に高速化されますが、オープンソース プロジェクトでのモジュールの実際の影響を観察できるようになるまでには、しばらく時間がかかる可能性があります。

プリコンパイル済みヘッダー

モジュールを待っていると、おそらくプリコンパイル済みヘッダーの恩恵を受けることができます.CMake 3.16 はそれらをサポートしており、サードパーティのライブラリや、独自のコードでさえフルビルドまで高速化するのに非常に有益です.

テンプレートのインスタンス化のキャッシュ

C++ コンパイラが行う最もコストのかかる処理の 1 つは、テンプレートのインスタンス化です。

現在ほとんど死んでいるプロジェクト zapcc は、翻訳単位全体でテンプレートのインスタンス化をキャッシュすることを目的としており、コンパイル時の速度が 2 ~ 5 倍向上することがベンチマークされました。残念ながら、51 は clang の古いフォークに基づいており、この技術を主流のコンパイラに統合する作業は計画されていないと思います.

測定

MSVC と Clang の両方に、ビルドの最もコストのかかる部分をプロファイリングするためのツールがあります。ビルド時間を最適化したい場合は、これらのツールを使用することを強くお勧めします。なぜなら、すべてのパフォーマンス チューニング作業と同様に、ボトルネックの原因についての直感がおそらく間違っていることが判明するからです。 .

コンパイルを高速化するその他のトリック

このビデオでは、コンパイル速度を向上させるための多くの洞察を提供しています。 ld と 75 の代わりに 82 の代わりに .Windows を使用している場合は、92 を呼び出すたびに、読み書きするすべてのファイルをウイルス対策ソフトウェアが検査しないようにしてください。 .

大規模なコンパイル

大規模な組織では、コンパイル時間を改善するために他のツールを利用できます:

  • 100 などの分散ビルド と 117 多くのマシンでワークロードを共有するように設定できます。
  • 一部の企業では、従業員に ssh を介して強力なリモート ハードウェアでコンパイルさせています。これには、ユーザーが非常に強力なハードウェアにアクセスできると同時に、リソースを最適に利用できるというメリットがあります。
  • 両方のソリューションを組み合わせることができます。

コンパイル時に設計しない

インターフェイス レベルでは、コンパイル時間は優先順位と目標の一番下にある必要があります。ここに秘密はありません。コンパイル時間の改善は簡単です:抽象化を取り除き、ジェネリック性を取り除きます.それはあなたが望むものですか?おそらくそうではありません.この記事では、コンパイル時間を改善するための多くの解決策を紹介しました。必要のないヘッダーを含めないことで、いくつかの改善が得られますが、残念ながら、これらを追跡するのは困難です。数年前。

コンパイル時間と ABI 破壊標準の変更

ビルド システムとインフラストラクチャに投資しないと、ビルドに何時間も、何日もかかる可能性があります。数週間?しかし、標準ではせいぜい 3 年に 1 回、ABI に影響を与える可能性のある変更が行われる程度です。残りの時間はプログラムが最適に実行されていないことに比べれば、それほど多くはありません。 ABI を長期間にわたって安定した状態に保つ理由。

もちろん他にも考慮すべき点はたくさんありますが、それはまた別の機会に!

それまでは、

安全を確保してください!