PEAR
PEAR

Reputation: 706

Why does using LTO increase the size of my Rust binary?

Introduction

I finished a small Rust project (about 300 lines of code) with the following dependencies:

Problem

When using cargo build --release without further configuration, a 2.942.744 bytes (= 2,8 MiB) binary is generated. I tried to optimize this by enabling Link Time Optimization (LTO) in my Cargo.toml:

[profile.release]
lto = true

To my surprise, the binary grows, with a new size of 3.848.288 bytes (= 3,7 MiB).

How can this be explained? Is there any mistake I made configuring Cargo?

Upvotes: 23

Views: 10055

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 300399

What is LTO?

LTO means Link-Time Optimization. It is generally set up to use the regular optimization passes used to produce object files... at link time instead, or in addition.

Why does it matter?

A compiler does not inherently optimize for speed over size or size over speed; and therefore neither does LTO.

Instead, when invoking the compiler, the user selects a profile. For rustc:

  • O0, O1, O2 and O3 are optimizing for speed.
  • Os and Oz are optimizing for size.

LTO can be combined on top of any optimization level, and will follow the selected profile.

So why did the size increase?

By default, the [release] profile instructs cargo to invoke rustc with O2 or O3, which attempts to optimize for speed over size.

In particular, O3 can rely quite heavily on inlining. Inlining is all about giving more context to the optimizer, and therefore more optimization opportunities... LTO offers more chances to apply inlining (more known functions), and here it appears that more inlining happened.

So why did this blog post claim it reduced size?

It also reduces size. Possibly.

By giving more context, the optimizer/linker can realize that some portion of the code or dependencies are not used at all, and therefore can be elided.

If using Os or Oz, the size is near certain to go down.

If using O2 or O3, unused code is removed while inlining adds more code, so it's quite unpredictable whether the end result is bigger or smaller.

So, LTO?

LTO gives the optimizer a better opportunity at optimizing, so it's a good default for Releases.

Just remember that cargo leans toward speed over size by default, and if this does not suit you, you may want to select another optimization direction.

Upvotes: 40

user541686
user541686

Reputation: 210765

Probably because of inlining, which can increase code size to increase speed.

Upvotes: 6

Related Questions