web-dev-qa-db-ja.com

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

前書き

次の依存関係を持つ小さなRustプロジェクト(約300行のコード))を終了しました:

問題

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

[profile.release]
lto = true

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

これはどのように説明できますか? Cargoの設定に間違いはありますか?

16
PEAR

LTOとは

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

なぜそれが重要なのですか?

コンパイラーは、本質的にサイズよりも速度またはサイズよりも速度を優先して最適化しません。したがって、LTOも行いません。

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

  • O0O1O2およびO3は速度を最適化しています。
  • OsOzはサイズを最適化しています。

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

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

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

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

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

サイズも小さくなります。たぶん。

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

OsまたはOzを使用している場合、サイズは確実に減少します。

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

だから、LTO?

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

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

26
Matthieu M.

おそらくインライン化が原因で、コードサイズを増やして速度を上げることができます。

5
user541686