web-dev-qa-db-ja.com

コンパイラーは、コンパイル時間を短縮するためにマルチスレッドを利用しますか?

コンパイラのコースを正しく覚えていると、一般的なコンパイラの概要は次のようになります。

  • 字句解析器はソースコードをスキャンします(またはスキャン機能を呼び出します)文字ごと
  • 入力文字の文字列は、語彙素の辞書と照合して妥当性がチェックされます
  • 語彙素が有効な場合、対応するトークンとして分類されます。
  • パーサーは、トークンの組み合わせの構文を検証します。 token-by-token

ソースコードを4分の1(または任意の分母)に分割し、スキャンと解析のプロセスをマルチスレッド化することは理論的に可能ですか?マルチスレッドを利用するコンパイラーはありますか?

16
8protons

大規模なソフトウェアプロジェクトは通常、比較的独立してコンパイルできる多くのコンパイルユニットで構成されているため、コンパイルは、コンパイラーを複数回並行して呼び出すことにより、非常に大まかな粒度で並列化されることがよくあります。これはOSプロセスのレベルで発生し、適切なコンパイラではなくビルドシステムによって調整されます。これはあなたが尋ねたものではないことを私は理解していますが、それはほとんどのコンパイラの並列化に最も近いものです。

何故ですか?まあ、コンパイラが行う作業の多くは、簡単には並列化に向いていません。

  • 入力をいくつかのチャンクに分割して、それらを個別にLexすることはできません。簡単にするために、字句境界で分割したい(字句の途中でスレッドが開始されないようにする)必要がありますが、字句境界を決定するには、多くのコンテキストが必要になる可能性があります。たとえば、ファイルの途中でジャンプする場合は、文字列リテラルにジャンプしていないことを確認する必要があります。しかし、これを確認するには、基本的に前に来たすべてのキャラクターを調べる必要があります。その上、字句解析が最新の言語のコンパイラのボトルネックになることはめったにありません。
  • 解析は並列化がさらに困難です。字句解析のための入力テキストの分割に関するすべての問題は、解析のためのトークンの分割にも当てはまります。たとえば、関数の開始位置の決定は、基本的に関数の内容の解析を開始するのと同じくらい難しいです。これを回避する方法もあるかもしれませんが、それらは小さな利益のためにおそらく不釣り合いに複雑になります。解析も最大のボトルネックではありません。
  • 解析した後は、通常、名前解決を実行する必要がありますが、これは関係の巨大な織り交ぜられたネットにつながります。ここでメソッド呼び出しを解決するには、最初にこのモジュールのインポートを解決する必要があるかもしれませんが、それらはanotherコンパイルユニットなどで名前を解決する必要があります。言語にそれがある場合は、型推論でも同じです。

この後、少し簡単になります。型チェックと最適化、およびコード生成は、原則として、関数の粒度で並列化できます。おそらくこれほど多くのコンパイラーがこれを実行するかどうかはまだわかっていません。おそらく、これほど大きなタスクを同時に実行することは非常に困難です。また、ほとんどの大規模なソフトウェアプロジェクトには非常に多くのコンパイルユニットが含まれているため、「多数のコンパイラを並行して実行する」アプローチで、すべてのコア(場合によってはサーバーファーム全体)を占有するのに十分です。さらに、大規模なコンパイルタスクでは、ディスクI/Oが実際のコンパイル作業と同じくらいボトルネックになる可能性があります。

そうは言っても、コードの生成と最適化の作業を並列化するコンパイラーは知っています。 Rustコンパイラは、バックエンドの作業(LLVM、これには実際には「ミドルエンド」と見なされているコード最適化を実際に含む)を複数のスレッドに分割できます。これは「コード生成ユニット」と呼ばれます。上記の他の並列化の可能性とは対照的に、これは次の理由により経済的です。

  1. 言語のコンパイル単位がかなり大きい(たとえば、CやJavaと比較して)ため、コアよりも実行中のコンパイル単位が少ない可能性があります。
  2. 並列化される部分は通常、コンパイル時間の大部分を占めます。
  3. バックエンドの作業は、ほとんどの場合、恥ずかしいほど並列です。最適化して、各関数を個別にマシンコードに変換するだけです。もちろん、手続き間の最適化があり、codegenユニットはそれらを妨げてパフォーマンスに影響を与えますが、意味上の問題はありません。
29
user7043

コンパイルは「恥ずかしいほど並列」な問題です。

1つのファイルをコンパイルする時間を気にする人はいません。人々は1000個のファイルをコンパイルする時間を気にします。また、1000ファイルの場合、プロセッサの各コアは一度に1つのファイルをコンパイルして、すべてのコアを完全にビジー状態に保つことができます。

ヒント:「make」は、適切なコマンドラインオプションを指定すると、複数のコアを使用します。それがなければ、16コアシステムで1つのファイルを次々にコンパイルします。つまり、ビルドオプションを1行変更するだけで、16倍速くコンパイルできます。

2
gnasher729