Linking taking an inordinately long time

I've got a fairly concise Rust program that takes very long to link. Using the current nightly (rustc 1.43.0-nightly (823ff8cf1 2020-03-07)) and the -Ztime-passes flag I get the following:

time: 0.000; rss: 541MB link_binary_check_files_are_writeable
time: 4.511; rss: 541MB run_linker
time: 0.002; rss: 541MB link_binary_remove_temps
time: 4.515; rss: 541MB link_binary
time: 4.515; rss: 541MB link_crate
time: 0.013; rss: 541MB incr_comp_finalize_session_directory
time: 0.000; rss: 541MB llvm_dump_timing_file
time: 4.533; rss: 541MB link
time: 8.013; rss: 540MB         total
    Finished dev [unoptimized + debuginfo] target(s) in 8.20s

As you can see the link_binary stage of the build takes up over half(!) of the total build time.

If I reduce my code to just the following (ie get rid of almost everything except main and the imports):

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate lazy_static;

use google_api_auth::GetAccessToken;
use google_field_selector::FieldSelector;
use google_firestore1::Client;
use jwks_client::keyset::KeyStore;
use mut_static::MutStatic;
use serde::Deserialize;
use std::convert::Infallible;
use std::env;
use std::error::Error;
use std::sync::Arc;
use warp::http::StatusCode;
use warp::{reject, Filter, Rejection, Reply};
use yup_oauth2 as oauth;

lazy_static! {
    pub static ref KS: MutStatic<KeyStore> = { MutStatic::new() };
}

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
}

I get the following result:

time: 0.000; rss: 257MB link_binary_remove_temps
time: 2.560; rss: 257MB link_binary
time: 2.560; rss: 257MB link_crate
time: 0.001; rss: 257MB incr_comp_finalize_session_directory
time: 0.000; rss: 257MB llvm_dump_timing_file
time: 2.563; rss: 257MB link
time: 2.823; rss: 257MB         total
    Finished dev [unoptimized + debuginfo] target(s) in 3.04s

The linking stage now takes up almost 85% of the compile time. I'm not sure why this is the case, but it's pretty terrible for my code-compile-run iterations. Does anyone know why the linker is taking so long, and how I can speed it up?

Regards,
Maarten

1 Like

You may want to try lld instead of using the system linker: RUSTFLAGS="-Clinker-args=-fuse-ld=lld" cargo build Please note that the macOS version of lld is effectively unmaintained, so in that case you may want to try zld.

1 Like

That speeds it up quite a bit, thanks!

time: 0.246; rss: 259MB run_linker
time: 0.000; rss: 259MB link_binary_remove_temps
time: 0.247; rss: 259MB link_binary
time: 0.247; rss: 259MB link_crate
time: 0.001; rss: 259MB incr_comp_finalize_session_directory
time: 0.000; rss: 259MB llvm_dump_timing_file
time: 0.249; rss: 259MB link
time: 0.516; rss: 259MB         total
    Finished dev [unoptimized + debuginfo] target(s) in 0.73s

Question is though, why is there such a difference, and how do I make it permanent (ie how do I not have to set the envvar every time)?

Regards,
Maarten

You can set rustflags in a .cargo/config file either per-project or globally (in your home directory or some other common ancestor directory of all your projects). Though there may be some issues with rustflags set in one config file being overridden by another, if you have them at multiple levels of the directory tree.

The system linker on many systems is quite slow and for example often doesn't benefit much from multithreading. Lld however is made with multithreading in mind. Even without multithreading lld is faster than most system linkers.

https://lld.llvm.org/

Thanks for the replies. With the following in my ~/.cargo/config things run a lot faster:

[build]
rustflags = ["-Clink-args=-fuse-ld=lld"]

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.