LTO を使用すると Rust バイナリのサイズが大きくなるのはなぜですか? 質問する

LTO を使用すると Rust バイナリのサイズが大きくなるのはなぜですか? 質問する

導入

私は、次の依存関係を持つ小さな Rust プロジェクト (約 300 行のコード) を完成させました。

問題

追加の設定なしで使用するとcargo build --release、2.942.744 バイト (= 2.8 MiB) のバイナリが生成されます。私は、リンク時間最適化 (LTO) を有効にしてこれを最適化しようとしましたCargo.toml

[profile.release]
lto = true

驚いたことに、バイナリは大きくなり、新しいサイズは 3.848.288 バイト (= 3.7 MiB) になりました。

これはどう説明すればいいのでしょうか? Cargo の設定で何か間違いがあったのでしょうか?

ベストアンサー1

LTOとは何ですか?

LTO はリンク時最適化を意味します。通常、オブジェクト ファイルを生成するために使用される通常の最適化パスをリンク時の代わりに、またはそれに加えて使用するように設定されます。

なぜそれが重要なのでしょうか?

コンパイラは本質的に、サイズよりも速度を、あるいは速度よりもサイズを優先して最適化するものではありません。したがって、LTO も同様です。

代わりに、コンパイラを呼び出すときに、ユーザーはプロファイルを選択しますrustc

  • O0、、O1は速度を最適化していますO2O3
  • OsOzサイズを最適化しています。

LTO は任意の最適化レベルと組み合わせることができ、選択したプロファイルに従います。

では、なぜサイズが大きくなったのでしょうか?

デフォルトでは、プロファイルはまたはで呼び出すように[release]指示します。cargorustcO2O3試みサイズよりも速度を最適化します。

特に、O3インライン化に大きく依存する可能性があります。インライン化とは、オプティマイザーにより多くのコンテキストを提供し、したがってより多くの最適化の機会を提供することです... LTO は、インライン化を適用する機会を増やします (より多くの既知の関数)。ここでは、より多くのインライン化が行われたように見えます。

ではなぜこのブログ投稿サイズが縮小されたと主張しますか?

サイズも小さくなります。可能性はあります。

より多くのコンテキストを提供することで、オプティマイザー/リンカーは、コードまたは依存関係の一部がまったく使用されていないことを認識し、省略することができます。

Osまたは を使用するとOz、サイズが小さくなることはほぼ確実です。

O2または を使用するとO3、未使用のコードは削除され、インライン化によってコードが追加されるため、最終結果が大きくなるか小さくなるかはまったく予測できません。

それで、LTOですか?

LTO はオプティマイザーに最適化の機会をより多く与えるため、リリースのデフォルトとして適しています。

デフォルトではサイズよりも速度が優先されることを覚えておいてくださいcargo。これが適していない場合は、別の最適化の方向を選択することをお勧めします。

おすすめ記事