テクノロジー : リンクを高速化するための秘訣

ARTICLE BY:
POSTED:

TAGS:

C/C++プログラムミングコードのビルドでは、リンク処理は最終ステージとなります。開発に携わっていると、開発中のプログラムを実行したり、デバッグ前には、リンク処理が終わるのを待たなければならないことがあります。プロセス内の遅延は開発を遅らせ、フラストレーションもたまります。

今回は、いらいらを少しでも解消するため、リンク時間をうまくコントロールするためのヒントをご紹介します。ここでは、次のような内容をご紹介しています。

  • リンカを大好きになる (!)
  • ワークステーションで「スーパーチャージ」を発動
  • 入出力のサイズを小さくする
  • コストの高いオプションは必要なときだけ使う

リンカを大好きになる

「心から」リンカを大好きになる必要はありませんが、リンカで何ができるのかを知ることには、好奇心がそそられるかもしれません。リンカは、高レベルでオブジェクトファイルを読み取り、コードとデータをレイアウトし、アドレスを解消して、結果を出力ファイルにコピーします。この操作は、次の3つの段階で行われます。

  1. スキャン:リンカはオブジェクトファイルを検査し、オブジェクトファイルに含まれているコードやデータのセクション上で情報を収集し、さらにこういったセクションを最終出力の所定の位置に移動するとき適用する必要のあるリロケーション情報も収集します。
  2. レイアウト:スキャン中に収集された情報は、出力ファイルをどのように構成するのかを計算するのに使用されます。
  3. 出力:オブジェクトファイルが改訂されます。ここではコードやデータをコピーし、リロケーションを適用し、それらを出力ファイルの正しい位置に移します。

リンカは、第一にファイルの読み書きに取りかかります。次に、リンカはほとんどの時間をスキャン (30%) と出力 (50%) に充てます。

リンカは正確さと効率性を実現すべく設計されています。この3段階のそれぞれは、インプットのサイズに比例するはずです。ただ、ここにはどうしても破れない、スピード制限があります。一連の入力の完全リンクには、ファイル連結時より時間がかかります。

ワークステーションで「スーパーチャージ」を発動

ファイルのIOは大きなリンクのボトルネックとなります。コードがディスクの数ギガバイトを占有してしまう、ということもそう珍しいことではありません。このくらいボリュームのあるデータのリンクを行う上で、まずお勧めするのは、これに適したハードウェアに投資する、という点です。具体的には、高速ファイルシステムアクセスを行うためにSSDを使い、ファイルシステムに適当な空き容量があることを確認し、入出力をローカルで維持する(つまりネットワーク共有では行わない)ということをお試しください。オペレーティング システムのファイルキャッシュを最大限に生かし、ハードなページ フォールトを最低限に抑えるため、RAMはできるだけたくさんインストールしてください。CPUコアの数を増やしても、リンク時間の短縮にはつながらないことがあります。処理それ自体ではなく、ファイルのIOがボトルネックだからです。

また、オペレーティング システムの管理ツールを使い、ファイル システムに他の何がアクセスしているのかをチェックしてみるのも、やるだけの価値はあります。たとえば、バージョンコントロール外にあるファイルをチェックするのと同時にリンクするよう試してみてください。リンクは遅くなるはずです。

ウォームリンクとコールドリンク

まったく同じオプションとインプットを使って、あるリンク処理が2回実行された場合、2回目の実行にはほんの何分の一かの時間しかかかりません。これはオペレーティングシステムが最初のリンクでアクセスするファイルのキャッシュにRAMを使うからで、これにより後続のリンクにかかる、物理的なディスクアクセスタイムが短縮されます。この第1リンクを「コールドリンク」と呼び、これに続く、第1リンクより高速なリンクを「ウォームリンク」と呼びます。システムメモリを増設すると、後続リンクで入力ファイルがメモリ内に存在する確率が高くなります。

ウォーム・コールドリンク時間のグラフ

スローリンクでも「リンクなし」より速い

時間のかかるビルドの最後にやっと到達したとします。しかし、リンカが必要なシンボルを見つけられずにビルドに失敗したりすると、いらいらしますね。それどころか、このエラーの警告は、リンカが各種処理を行った後でなければ表示されません。このエラーを修正するためには、入力自体を修正しなければならず、さらに後続のリビルドには再びリンク設定が必要になってきます。

このような場合には、一呼吸おいてください、としか言えません。ビルドに失敗してしまう理由に心当たりはありますか?入力ファイルは全部追加しましたか? 新しい関数やプログラムに必要となるデータの定義はしましたか?

コストの高いオプションは必要なときだけ使う

リンクオプションの中には、使用するとリンク時間が長くなるものがあります。それらを以下に示します。

  • デッドストリッピングと重複除外:使用していない関数やデータをストリップし、重複したシンボルを抹消すると、最終リンク実行可能ファイルのロード可能サイズが縮小されますが、リンカではかなり大量の余分な作業をこなさなければなりません。
  • LTO:リンク時最適化 (LTO) は、パワフルな最適化機能です。この機能を有効にすると、コンパイラは中間形式でオブジェクト ファイルを生成します。こういった中間オブジェクトファイルがリンクされた場合には、これらは全体としてひとつのものとしてまとめられ、最適化されます。このプロセスはCPUとメモリに集中します。

上述した他のオプションとは違い、LTOの利用は段階的に行われます。LTOを使った場合に得られるものが、インプットの何分の一かのコンパイルにより実現するのならば、ビルド時間はそれほど影響を受けません。

入出力のサイズを小さくする

入力サイズを小さくするには、入力の中の未使用のコードをすべて削除してください。

ビルドがうまく高速化できますように!

トップに戻る