Rust Compilation size and embedded string

build size

When we embedded a CSV file in our code I noticed that the size of compiled executable jumped by a lot more than the size of the embedded string.

I could not sleep well tonight, so when I woke up at 4 am I had to do a little experiment. I wanted to see how the compiled size changes as the size of the embedded string changes.

So I created a new crate:

cargo new compile-size

The content of the crate was:

fn main() {
    println!("Hello World!");
}

Compiled it in release mode:

cargo build --release

and checked the size:

ls -l target/release/compile-size

I changed the embedded string, first I removed the whole "Hello World!" and left it with an empty string, then I started to add characters to it.

0

fn main() {
    println!("");
}

10

fn main() {
    println!("0123456789");
}

Embedded string lengths vs Compile size in release mode

String length Compile size Difference
0 4,654,808
1,343 4,654,808
1,344 4,658,904 4,096

So when Rust compiled the code with the embedded string it creates space for up to 1343 characters and it had to create a larger binary only when the embedded string was 1,344 character long.

String length was measured by .len().

Minimizing compiled size.

There are several ways to make the compiled binary smaller. The min-sized-rust repository contains explanations on the various methods. From this post I copied the suggested instructions by adding the following to Cargo.toml.

[profile.release]
opt-level = 'z'     # Optimize for size
lto = true          # Enable link-time optimization
codegen-units = 1   # Reduce number of codegen units to increase optimizations
panic = 'abort'     # Abort on panic
strip = true        # Strip symbols from binary*

Then I ran the experiment again. This time I got the following numbers:

String length Compile size Difference
0 326,072
3,224 326,072
3,225 330,168 4,096

First of all, the total size was reduced by more than 90%.

The embedded string could now grow to 3,224 characters without a change in the compiled size.

Something that I have not measured, but was obvious as I ran the experiment, the compilation took longer.

Environment

I ran this experiment on this environment:

$ rustup show
Default host: x86_64-unknown-linux-gnu
rustup home:  /home/gabor/.rustup

stable-x86_64-unknown-linux-gnu (default)
rustc 1.73.0 (cc66ad468 2023-10-03)

Conclusion

I still don't know why isn't the relationship between the embedded string and the compiled code is linear, but "wasting" up to 4,096 bytes is not a big issue.

I should probably add the optimizations to the releases of by command-line tools.

I found a page monitoring the performance of Rust versions, but as far as I can see it only (or primarily) monitors the speed performance and not the compiled size.

There is a lot more for me to learn about build optimizations.

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo