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


16

コンパイラのコースを正しく覚えている場合、典型的なコンパイラの概要は次のとおりです。

  • 字句解析プログラムは、ソースコードを文字ごとにスキャンします(またはスキャン関数を呼び出します)。
  • 入力文字列は、妥当性について語彙素の辞書と照合されます
  • 語彙素が有効な場合、対応するトークンとして分類されます
  • パーサーは、トークンの組み合わせの構文を検証します。トークンごとのトークン

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




1
@RobertHarvey最初のリンクの一番の答えは、「コンパイラー自体はまだシングルスレッドです」と書いています。だからそれはノーですか?
8プロトン

残りの回答、特にこの回答と、私が投稿した2番目のリンクを読むことをお勧めします。
ロバートハーヴェイ

2
@RobertHarveyあなたが投稿した2番目のリンクは、それが言っていることを理解していることから、コンパイルされたアプリケーションのマルチスレッドバージョンを生成するコンパイラについて話している。それはコンパイラ自体に関するものではありません。共有リソースと、対応に時間を割いていただきありがとうございます。
8プロトン

回答:


29

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

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

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

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

とはいえ、コード生成と最適化の作業を並列化するコンパイラーは知っています。Rustコンパイラーは、バックエンド作業(LLVM、実際には従来「ミドルエンド」と考えられていたコード最適化を含む)を複数のスレッドに分割できます。これは「コード生成単位」と呼ばれます。上記の他の並列化の可能性とは対照的に、これは次の理由で経済的です。

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

2

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

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

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

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